From de6ac33ec186d63eaf2e77800a61d2d743357edd Mon Sep 17 00:00:00 2001 From: Vasily Date: Thu, 10 Jan 2019 15:39:37 +0300 Subject: [PATCH] Unminify using 1.5.323 Repo with tag: https://github.com/MediaBrowser/emby-webcomponents/tree/1.5.323 --- .../actionsheet/actionsheet.css | 89 +- .../actionsheet/actionsheet.js | 416 +- .../emby-webcomponents/alert/alert.js | 46 +- .../emby-webcomponents/alert/nativealert.js | 29 +- .../alphanumericshortcuts.js | 121 +- .../alphapicker/alphapicker.js | 349 +- .../emby-webcomponents/alphapicker/style.css | 106 +- .../appfooter/appfooter.css | 13 +- .../emby-webcomponents/appfooter/appfooter.js | 50 +- .../emby-webcomponents/appsettings.js | 183 +- .../emby-webcomponents/backdrop/backdrop.js | 396 +- .../emby-webcomponents/backdrop/style.css | 24 +- .../emby-webcomponents/browser.js | 367 +- .../browserdeviceprofile.js | 1126 ++- .../emby-webcomponents/cardbuilder/card.css | 705 +- .../cardbuilder/cardbuilder.js | 2297 ++++-- .../cardbuilder/chaptercardbuilder.js | 155 +- .../cardbuilder/peoplecardbuilder.js | 26 +- .../cardbuilder/roundcard.css | 13 +- .../chromecast/chromecasthelpers.js | 245 +- .../chromecast/chromecastplayer.js | 1331 +++- .../emby-webcomponents/clearbutton.css | 6 +- .../collectioneditor/collectioneditor.js | 298 +- .../emby-webcomponents/confirm/confirm.js | 56 +- .../confirm/nativeconfirm.js | 34 +- .../emby-webcomponents/datetime.js | 305 +- .../emby-webcomponents/deletehelper.js | 70 +- .../emby-webcomponents/dialog/dialog.js | 165 +- .../dialoghelper/dialoghelper.css | 172 +- .../dialoghelper/dialoghelper.js | 519 +- .../displaysettings/displaysettings.js | 385 +- .../displaysettings.template.html | 6 +- .../emby-webcomponents/dom.js | 192 +- .../emby-button/emby-button.css | 192 +- .../emby-button/emby-button.js | 110 +- .../emby-button/paper-icon-button-light.js | 23 +- .../emby-checkbox/emby-checkbox.css | 127 +- .../emby-checkbox/emby-checkbox.js | 147 +- .../emby-collapse/emby-collapse.css | 36 +- .../emby-collapse/emby-collapse.js | 121 +- .../emby-connect/connecthelper.js | 237 +- .../emby-input/emby-input.css | 28 +- .../emby-input/emby-input.js | 163 +- .../emby-itemrefreshindicator.js | 75 +- .../emby-itemscontainer.js | 614 +- .../emby-progressring/emby-progressring.css | 106 +- .../emby-progressring/emby-progressring.js | 112 +- .../emby-radio/emby-radio.css | 76 +- .../emby-radio/emby-radio.js | 58 +- .../emby-scrollbuttons/emby-scrollbuttons.css | 53 +- .../emby-scrollbuttons/emby-scrollbuttons.js | 210 +- .../emby-scroller/emby-scroller.js | 277 +- .../emby-select/emby-select.css | 94 +- .../emby-select/emby-select.js | 155 +- .../emby-slider/emby-slider.css | 167 +- .../emby-slider/emby-slider.js | 319 +- .../emby-tabs/emby-tabs.css | 44 +- .../emby-webcomponents/emby-tabs/emby-tabs.js | 409 +- .../emby-textarea/emby-textarea.css | 27 +- .../emby-textarea/emby-textarea.js | 161 +- .../emby-toggle/emby-toggle.css | 99 +- .../emby-toggle/emby-toggle.js | 62 +- .../emby-webcomponents/fetchhelper.js | 132 +- .../emby-webcomponents/filedownloader.js | 16 +- .../emby-webcomponents/filesystem.js | 15 +- .../filtermenu/filtermenu.js | 373 +- .../emby-webcomponents/flexstyles.css | 47 +- .../emby-webcomponents/flvjs/flv.min.js | 6284 +---------------- .../emby-webcomponents/focusmanager.js | 573 +- .../emby-webcomponents/fonts/fonts.css | 32 +- .../emby-webcomponents/fonts/fonts.sized.css | 29 +- .../fonts/material-icons/style.css | 13 +- .../emby-webcomponents/formdialog.css | 82 +- .../fullscreen/fullscreen-dc.js | 28 +- .../fullscreen/fullscreenmanager.js | 88 +- .../emby-webcomponents/globalize.js | 312 +- .../guide/guide-settings.js | 185 +- .../emby-webcomponents/guide/guide.css | 391 +- .../emby-webcomponents/guide/guide.js | 1447 +++- .../emby-webcomponents/guide/programs.css | 14 +- .../emby-webcomponents/headroom/headroom.css | 10 +- .../emby-webcomponents/headroom/headroom.js | 399 +- .../homescreensettings/homescreensettings.js | 634 +- .../homescreensettingsdialog.js | 101 +- .../homesections/homesections.css | 9 +- .../homesections/homesections.js | 1362 +++- .../htmlaudioplayer/plugin.js | 537 +- .../htmlvideoplayer/htmlmediahelper.js | 436 +- .../htmlvideoplayer/plugin.js | 2013 ++++-- .../htmlvideoplayer/style.css | 62 +- .../imagedownloader/imagedownloader.js | 450 +- .../imageeditor/imageeditor.css | 10 +- .../imageeditor/imageeditor.js | 573 +- .../images/basicimagefetcher.js | 38 +- .../emby-webcomponents/images/imagehelper.js | 259 +- .../emby-webcomponents/images/style.css | 46 +- .../imageuploader/imageuploader.js | 195 +- .../imageuploader/style.css | 12 +- .../indicators/indicators.css | 73 +- .../indicators/indicators.js | 284 +- .../emby-webcomponents/input/api.js | 302 +- .../emby-webcomponents/input/gamepadtokey.js | 455 +- .../emby-webcomponents/input/mouse.js | 162 +- .../emby-webcomponents/inputmanager.js | 266 +- .../emby-webcomponents/itemcontextmenu.js | 897 ++- .../emby-webcomponents/itemhelper.js | 390 +- .../itemidentifier/itemidentifier.js | 576 +- .../emby-webcomponents/itemsrefresher.js | 298 +- .../emby-webcomponents/layoutmanager.js | 74 +- .../lazyloader/lazyedgehack.css | 5 +- .../lazyloader-intersectionobserver.js | 126 +- .../lazyloader/lazyloader-scroll.js | 232 +- .../emby-webcomponents/listview/listview.css | 226 +- .../emby-webcomponents/listview/listview.js | 592 +- .../emby-webcomponents/loading/loader2.gif | Bin 11493 -> 36058 bytes .../loading/loading-legacy.css | 4 +- .../loading/loading-legacy.js | 33 +- .../loading/loading-lite.css | 327 +- .../loading/loading-lite.js | 80 +- .../loadingdialog/loadingdialog.js | 115 +- .../emby-webcomponents/maintabsmanager.js | 284 +- .../emby-webcomponents/mediainfo/fresh.png | Bin 13458 -> 18192 bytes .../mediainfo/mediainfo.css | 56 +- .../emby-webcomponents/mediainfo/mediainfo.js | 750 +- .../emby-webcomponents/mediainfo/rotten.png | Bin 9991 -> 14428 bytes .../metadataeditor/metadataeditor.js | 1293 +++- .../metadataeditor/personeditor.js | 115 +- .../emby-webcomponents/multidownload.js | 77 +- .../multiselect/multiselect.css | 19 +- .../multiselect/multiselect.js | 760 +- .../native-promise-only/lib/npo.src.js | 519 +- .../native-promise-only/test_adapter.js | 33 +- .../notifications/badge.png | Bin 39306 -> 3917 bytes .../notifications/notificationicon.png | Bin 39306 -> 3917 bytes .../notifications/notifications.js | 316 +- .../nowplayingbar/nowplayingbar.css | 111 +- .../nowplayingbar/nowplayingbar.js | 834 ++- .../emby-webcomponents/packagemanager.js | 184 +- .../emby-webcomponents/pagejs/page.js | 1295 +++- .../emby-webcomponents/photoplayer/plugin.js | 53 +- .../playback/autoplaydetect.js | 77 +- .../playback/brightnessosd.js | 150 +- .../playback/experimentalwarnings.js | 94 +- .../emby-webcomponents/playback/iconosd.css | 23 +- .../playback/mediasession.js | 259 +- .../playback/nowplayinghelper.js | 112 +- .../playback/playaccessvalidation.js | 59 +- .../playback/playbackmanager.js | 4968 +++++++++---- .../playback/playbackorientation.js | 60 +- .../playback/playbackvalidation.js | 79 +- .../playback/playerselection.js | 361 +- .../playback/playersettingsmenu.js | 416 +- .../playback/playmethodhelper.js | 25 +- .../playback/playqueuemanager.js | 276 +- .../playback/remotecontrolautoplay.js | 59 +- .../emby-webcomponents/playback/volumeosd.js | 143 +- .../playbacksettings/playbacksettings.js | 362 +- .../playerstats/playerstats.css | 33 +- .../playerstats/playerstats.js | 535 +- .../playlisteditor/playlisteditor.js | 309 +- .../emby-webcomponents/playmenu.js | 76 +- .../emby-webcomponents/pluginmanager.js | 172 +- .../emby-webcomponents/polyfills/array.js | 37 +- .../emby-webcomponents/polyfills/bind.js | 37 +- .../polyfills/objectassign.js | 35 +- .../emby-webcomponents/polyfills/raf.js | 44 +- .../emby-webcomponents/prompt/nativeprompt.js | 36 +- .../emby-webcomponents/prompt/prompt.js | 120 +- .../emby-webcomponents/qualityoptions.js | 337 +- .../recordingcreator/empty.png | Bin 68 -> 156 bytes .../recordingcreator/recordingbutton.js | 136 +- .../recordingcreator/recordingcreator.css | 24 +- .../recordingcreator/recordingcreator.js | 235 +- .../recordingcreator/recordingeditor.js | 181 +- .../recordingcreator/recordingfields.css | 6 +- .../recordingcreator/recordingfields.js | 404 +- .../recordingcreator/recordinghelper.js | 273 +- .../recordingcreator/seriesrecordingeditor.js | 288 +- .../refreshdialog/refreshdialog.js | 190 +- .../registrationservices.js | 869 ++- .../emby-webcomponents/require/requirecss.js | 90 +- .../emby-webcomponents/require/requiretext.js | 53 +- .../ResizeObserver.js | 1151 ++- .../emby-webcomponents/router.js | 940 ++- .../emby-webcomponents/sanitizefilename.js | 104 +- .../scroller/smoothscroller.js | 1219 +++- .../emby-webcomponents/scrollhelper.js | 138 +- .../emby-webcomponents/scrollstyles.css | 56 +- .../search/searchfields.css | 9 +- .../emby-webcomponents/search/searchfields.js | 130 +- .../search/searchresults.js | 912 ++- .../serverrestartdialog.js | 201 +- .../serviceworker/notifications.js | 55 +- .../emby-webcomponents/serviceworker/sync.js | 8 +- .../emby-webcomponents/sessionplayer.js | 622 +- .../emby-webcomponents/shell.js | 19 +- .../emby-webcomponents/shortcuts.js | 515 +- .../emby-webcomponents/skinmanager.js | 421 +- .../emby-webcomponents/slideshow/slideshow.js | 708 +- .../emby-webcomponents/slideshow/style.css | 108 +- .../emby-webcomponents/sortmenu/sortmenu.js | 136 +- .../emby-webcomponents/staticbackdrops.js | 165 +- .../emby-webcomponents/strings/ar.json | 1372 ++-- .../emby-webcomponents/strings/be-by.json | 1372 ++-- .../emby-webcomponents/strings/bg-bg.json | 1372 ++-- .../emby-webcomponents/strings/ca.json | 1372 ++-- .../emby-webcomponents/strings/cs.json | 1372 ++-- .../emby-webcomponents/strings/da.json | 1372 ++-- .../emby-webcomponents/strings/de.json | 1372 ++-- .../emby-webcomponents/strings/el.json | 1372 ++-- .../emby-webcomponents/strings/en-gb.json | 1372 ++-- .../emby-webcomponents/strings/en-us.json | 1348 ++-- .../emby-webcomponents/strings/es-ar.json | 1372 ++-- .../emby-webcomponents/strings/es-mx.json | 1372 ++-- .../emby-webcomponents/strings/es.json | 1372 ++-- .../emby-webcomponents/strings/fi.json | 1372 ++-- .../emby-webcomponents/strings/fr-ca.json | 1372 ++-- .../emby-webcomponents/strings/fr.json | 1372 ++-- .../emby-webcomponents/strings/gsw.json | 1372 ++-- .../emby-webcomponents/strings/he.json | 1372 ++-- .../emby-webcomponents/strings/hr.json | 1372 ++-- .../emby-webcomponents/strings/hu.json | 1372 ++-- .../emby-webcomponents/strings/id.json | 1372 ++-- .../emby-webcomponents/strings/it.json | 1372 ++-- .../emby-webcomponents/strings/kk.json | 1372 ++-- .../emby-webcomponents/strings/ko.json | 1372 ++-- .../emby-webcomponents/strings/lt-lt.json | 1372 ++-- .../emby-webcomponents/strings/ms.json | 1372 ++-- .../emby-webcomponents/strings/nb.json | 1372 ++-- .../emby-webcomponents/strings/nl.json | 1372 ++-- .../emby-webcomponents/strings/pl.json | 1372 ++-- .../emby-webcomponents/strings/pt-br.json | 1372 ++-- .../emby-webcomponents/strings/pt-pt.json | 1372 ++-- .../emby-webcomponents/strings/ro.json | 1372 ++-- .../emby-webcomponents/strings/ru.json | 1372 ++-- .../emby-webcomponents/strings/sk.json | 1372 ++-- .../emby-webcomponents/strings/sl-si.json | 1372 ++-- .../emby-webcomponents/strings/sv.json | 1372 ++-- .../emby-webcomponents/strings/tr.json | 1372 ++-- .../emby-webcomponents/strings/uk.json | 1372 ++-- .../emby-webcomponents/strings/vi.json | 1372 ++-- .../emby-webcomponents/strings/zh-cn.json | 1372 ++-- .../emby-webcomponents/strings/zh-hk.json | 1372 ++-- .../emby-webcomponents/strings/zh-tw.json | 1372 ++-- .../subtitleeditor/subtitleeditor.css | 4 +- .../subtitleeditor/subtitleeditor.js | 571 +- .../subtitleappearancehelper.js | 285 +- .../subtitlesettings/subtitlesettings.js | 240 +- .../sync/emby-downloadbutton.js | 223 +- .../emby-webcomponents/sync/sync.js | 825 ++- .../emby-webcomponents/sync/syncjobeditor.js | 563 +- .../emby-webcomponents/sync/syncjoblist.js | 476 +- .../emby-webcomponents/tabbedview/itemstab.js | 701 +- .../tabbedview/tabbedview.js | 133 +- .../emby-webcomponents/thememediaplayer.js | 121 +- .../themes/appletv/theme.css | 379 +- .../themes/blueradiance/bg.jpg | Bin 955240 -> 1044963 bytes .../themes/blueradiance/theme.css | 370 +- .../themes/dark-green/theme.css | 344 +- .../themes/dark-red/theme.css | 358 +- .../emby-webcomponents/themes/dark/theme.css | 353 +- .../themes/halloween/theme.css | 374 +- .../themes/light-blue/theme.css | 346 +- .../themes/light-green/theme.css | 349 +- .../themes/light-pink/theme.css | 347 +- .../themes/light-purple/theme.css | 347 +- .../themes/light-red/theme.css | 367 +- .../emby-webcomponents/themes/light/theme.css | 361 +- .../emby-webcomponents/themes/logodark.png | Bin 48917 -> 9967 bytes .../emby-webcomponents/themes/logowhite.png | Bin 50195 -> 10300 bytes .../emby-webcomponents/themes/wmc/theme.css | 378 +- .../emby-webcomponents/toast/toast.css | 15 +- .../emby-webcomponents/toast/toast.js | 50 +- .../emby-webcomponents/touchhelper.js | 202 +- .../upnextdialog/upnextdialog.css | 49 +- .../upnextdialog/upnextdialog.js | 339 +- .../userdatabuttons/emby-playstatebutton.js | 175 +- .../userdatabuttons/emby-ratingbutton.js | 210 +- .../userdatabuttons/userdatabuttons.css | 2 +- .../userdatabuttons/userdatabuttons.js | 337 +- .../usersettings/usersettings.js | 7 +- .../usersettings/usersettingsbuilder.js | 378 +- .../viewmanager/viewcontainer-lite.css | 105 +- .../viewmanager/viewcontainer-lite.js | 321 +- .../viewmanager/viewmanager.js | 203 +- .../viewsettings/viewsettings.js | 164 +- .../emby-webcomponents/visibleinviewport.js | 40 +- .../youtubeplayer/plugin.js | 468 +- .../youtubeplayer/style.css | 24 +- 289 files changed, 78483 insertions(+), 54701 deletions(-) diff --git a/src/bower_components/emby-webcomponents/actionsheet/actionsheet.css b/src/bower_components/emby-webcomponents/actionsheet/actionsheet.css index e22ca0bb7b..611fafa5ca 100644 --- a/src/bower_components/emby-webcomponents/actionsheet/actionsheet.css +++ b/src/bower_components/emby-webcomponents/actionsheet/actionsheet.css @@ -1,158 +1,113 @@ -.actionSheet, -.actionSheetContent { - display: -webkit-box; - display: -webkit-flex -} - -.actionSheetContent, -.actionSheetScroller { - -webkit-box-orient: vertical; - -webkit-box-direction: normal -} - .actionSheet { display: flex; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; padding: 0; border: none; max-height: 84%; - -webkit-border-radius: .1em !important; - border-radius: .1em !important + border-radius: .1em !important; } .actionsheet-not-fullscreen { max-width: 90%; - max-height: 90% + max-height: 90%; } .actionsheet-fullscreen { max-height: none; - -webkit-border-radius: 0 !important; - border-radius: 0 !important + border-radius: 0 !important; } .actionSheetContent-centered { text-align: center; - -webkit-box-align: center; - -webkit-align-items: center; - align-items: center + align-items: center; } .actionSheetContent { margin: 0 !important; padding: .4em 0 !important; - -webkit-flex-direction: column; flex-direction: column; display: flex; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; flex-grow: 1; - overflow: hidden + overflow: hidden; } .actionSheetMenuItem { font-weight: inherit; - -webkit-box-shadow: none; box-shadow: none; - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } -.actionSheetMenuItem:focus { - -webkit-transform: none !important; - transform: none !important -} + .actionSheetMenuItem:focus { + transform: none !important; + } .actionsheetListItemBody { - padding: .4em 1em .4em .6em !important + padding: .4em 1em .4em .6em !important; } .actionSheetItemText { white-space: nowrap; overflow: hidden; - -o-text-overflow: ellipsis; text-overflow: ellipsis; vertical-align: middle; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; flex-grow: 1; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - justify-content: flex-start + justify-content: flex-start; } .actionSheetItemAsideText { opacity: .7; font-size: 90%; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-pack: end; - -webkit-justify-content: flex-end; justify-content: flex-end; - -webkit-flex-shrink: 0; flex-shrink: 0; margin-left: 5em; - margin-right: .5em + margin-right: .5em; } .actionSheetScroller { + /* Override default style being applied by polymer */ margin-bottom: 0 !important; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-flex-direction: column; flex-direction: column; - width: 100% + width: 100%; } .actionSheetScroller-tv { max-height: 64%; max-width: 60%; - width: auto + width: auto; } .actionsheetDivider { height: .07em; margin: .25em 0; - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } .actionSheetTitle { margin: .6em 0 .7em !important; padding: 0 .9em; - -webkit-box-flex: 0; - -webkit-flex-grow: 0; - flex-grow: 0 + flex-grow: 0; } .actionSheetText { padding: 0 1em; - -webkit-box-flex: 0; - -webkit-flex-grow: 0; - flex-grow: 0 + flex-grow: 0; } .actionsheetMenuItemIcon { margin: 0 .85em 0 .45em !important; - padding: 0 !important + padding: 0 !important; } .actionsheet-xlargeFont { - font-size: 112% !important + font-size: 112%!important; } .btnCloseActionSheet { position: fixed; top: .75em; - left: .5em -} \ No newline at end of file + left: .5em; +} diff --git a/src/bower_components/emby-webcomponents/actionsheet/actionsheet.js b/src/bower_components/emby-webcomponents/actionsheet/actionsheet.js index 6c93bb2507..067d427aef 100644 --- a/src/bower_components/emby-webcomponents/actionsheet/actionsheet.js +++ b/src/bower_components/emby-webcomponents/actionsheet/actionsheet.js @@ -1,93 +1,363 @@ -define(["dialogHelper", "layoutManager", "globalize", "browser", "dom", "emby-button", "css!./actionsheet", "material-icons", "scrollStyles", "listViewStyle"], function(dialogHelper, layoutManager, globalize, browser, dom) { - "use strict"; +define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-button', 'css!./actionsheet', 'material-icons', 'scrollStyles', 'listViewStyle'], function (dialogHelper, layoutManager, globalize, browser, dom) { + 'use strict'; function getOffsets(elems) { - var doc = document, - results = []; - if (!doc) return results; - for (var box, elem, i = 0, length = elems.length; i < length; i++) elem = elems[i], box = elem.getBoundingClientRect ? elem.getBoundingClientRect() : { - top: 0, - left: 0 - }, results[i] = { - top: box.top, - left: box.left, - width: box.width, - height: box.height - }; - return results + + var doc = document; + var results = []; + + if (!doc) { + return results; + } + + var box; + var elem; + + for (var i = 0, length = elems.length; i < length; i++) { + + elem = elems[i]; + // Support: BlackBerry 5, iOS 3 (original iPhone) + // If we don't have gBCR, just use 0,0 rather than error + if (elem.getBoundingClientRect) { + box = elem.getBoundingClientRect(); + } else { + box = { top: 0, left: 0 }; + } + + results[i] = { + top: box.top, + left: box.left, + width: box.width, + height: box.height + }; + } + + return results; } function getPosition(options, dlg) { - var windowSize = dom.getWindowSize(), - windowHeight = windowSize.innerHeight, - windowWidth = windowSize.innerWidth; - if (windowWidth < 600 || windowHeight < 600) return null; + + var windowSize = dom.getWindowSize(); + var windowHeight = windowSize.innerHeight; + var windowWidth = windowSize.innerWidth; + + if (windowWidth < 600 || windowHeight < 600) { + return null; + } + var pos = getOffsets([options.positionTo])[0]; - "top" !== options.positionY && (pos.top += (pos.height || 0) / 2), pos.left += (pos.width || 0) / 2; - var height = dlg.offsetHeight || 300, - width = dlg.offsetWidth || 160; - pos.top -= height / 2, pos.left -= width / 2; - var overflowX = pos.left + width - windowWidth, - overflowY = pos.top + height - windowHeight; - return overflowX > 0 && (pos.left -= overflowX + 20), overflowY > 0 && (pos.top -= overflowY + 20), pos.top += options.offsetTop || 0, pos.left += options.offsetLeft || 0, pos.top = Math.max(pos.top, 10), pos.left = Math.max(pos.left, 10), pos + + if (options.positionY !== 'top') { + pos.top += (pos.height || 0) / 2; + } + + pos.left += (pos.width || 0) / 2; + + var height = dlg.offsetHeight || 300; + var width = dlg.offsetWidth || 160; + + // Account for popup size + pos.top -= height / 2; + pos.left -= width / 2; + + // Avoid showing too close to the bottom + var overflowX = pos.left + width - windowWidth; + var overflowY = pos.top + height - windowHeight; + + if (overflowX > 0) { + pos.left -= (overflowX + 20); + } + if (overflowY > 0) { + pos.top -= (overflowY + 20); + } + + pos.top += (options.offsetTop || 0); + pos.left += (options.offsetLeft || 0); + + // Do some boundary checking + pos.top = Math.max(pos.top, 10); + pos.left = Math.max(pos.left, 10); + + return pos; } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function show(options) { - var isFullscreen, dialogOptions = { - removeOnClose: !0, + + // items + // positionTo + // showCancel + // title + var dialogOptions = { + removeOnClose: true, enableHistory: options.enableHistory, - scrollY: !1 + scrollY: false }; - layoutManager.tv ? (dialogOptions.size = "fullscreen", isFullscreen = !0, !0, dialogOptions.autoFocus = !0) : (dialogOptions.modal = !1, dialogOptions.entryAnimation = options.entryAnimation, dialogOptions.exitAnimation = options.exitAnimation, dialogOptions.entryAnimationDuration = options.entryAnimationDuration || 140, dialogOptions.exitAnimationDuration = options.exitAnimationDuration || 100, dialogOptions.autoFocus = !1); - var dlg = dialogHelper.createDialog(dialogOptions); - isFullscreen ? dlg.classList.add("actionsheet-fullscreen") : dlg.classList.add("actionsheet-not-fullscreen"), dlg.classList.add("actionSheet"), options.dialogClass && dlg.classList.add(options.dialogClass); - var html = "", - scrollClassName = layoutManager.tv ? "scrollY smoothScrollY hiddenScrollY" : "scrollY", - style = ""; - if (options.items.length > 20) { - style += "min-width:" + (dom.getWindowSize().innerWidth >= 300 ? 240 : 200) + "px;" + + var backButton = false; + var isFullscreen; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + isFullscreen = true; + backButton = true; + dialogOptions.autoFocus = true; + } else { + + dialogOptions.modal = false; + dialogOptions.entryAnimation = options.entryAnimation; + dialogOptions.exitAnimation = options.exitAnimation; + dialogOptions.entryAnimationDuration = options.entryAnimationDuration || 140; + dialogOptions.exitAnimationDuration = options.exitAnimationDuration || 100; + dialogOptions.autoFocus = false; } - var i, length, option, itemIcon, renderIcon = !1, - icons = []; - for (i = 0, length = options.items.length; i < length; i++) option = options.items[i], itemIcon = option.icon || (option.selected ? "check" : null), itemIcon && (renderIcon = !0), icons.push(itemIcon || ""); - layoutManager.tv && (html += ''); - var center = options.title && !renderIcon; - center || layoutManager.tv ? html += '
' : html += '
', options.title && (html += '

', html += options.title, html += "

"), options.text && (html += '

', html += options.text, html += "

"); - var scrollerClassName = "actionSheetScroller"; - layoutManager.tv && (scrollerClassName += " actionSheetScroller-tv focuscontainer-x focuscontainer-y"), html += '
'; - var menuItemClass = "listItem listItem-button actionSheetMenuItem"; - for ((options.border || options.shaded) && (menuItemClass += " listItem-border"), options.menuItemClass && (menuItemClass += " " + options.menuItemClass), layoutManager.tv && (menuItemClass += " listItem-focusscale"), layoutManager.mobile && (menuItemClass += " actionsheet-xlargeFont"), i = 0, length = options.items.length; i < length; i++) - if (option = options.items[i], option.divider) html += '
'; - else { - var autoFocus = option.selected && layoutManager.tv ? " autoFocus" : "", - optionId = null == option.id || "" === option.id ? option.value : option.id; - html += "', itemIcon = icons[i], itemIcon ? html += '' + itemIcon + "" : renderIcon && !center && (html += ''), html += '
', html += '
', html += option.name || option.textContent || option.innerText, html += "
", option.secondaryText && (html += '
', html += option.secondaryText, html += "
"), html += "
", option.asideText && (html += '
', html += option.asideText, html += "
"), html += "" - } options.showCancel && (html += '
', html += '", html += "
"), html += "
", dlg.innerHTML = html, layoutManager.tv && centerFocus(dlg.querySelector(".actionSheetScroller"), !1, !0), dlg.querySelector(".btnCloseActionSheet") && dlg.querySelector(".btnCloseActionSheet").addEventListener("click", function() { - dialogHelper.close(dlg) - }); - var selectedId, timeout; - return options.timeout && (timeout = setTimeout(function() { - dialogHelper.close(dlg) - }, options.timeout)), new Promise(function(resolve, reject) { + + var dlg = dialogHelper.createDialog(dialogOptions); + + if (isFullscreen) { + dlg.classList.add('actionsheet-fullscreen'); + } else { + dlg.classList.add('actionsheet-not-fullscreen'); + } + + dlg.classList.add('actionSheet'); + + if (options.dialogClass) { + dlg.classList.add(options.dialogClass); + } + + var html = ''; + + var scrollClassName = layoutManager.tv ? 'scrollY smoothScrollY hiddenScrollY' : 'scrollY'; + var style = ''; + + // Admittedly a hack but right now the scrollbar is being factored into the width which is causing truncation + if (options.items.length > 20) { + var minWidth = dom.getWindowSize().innerWidth >= 300 ? 240 : 200; + style += "min-width:" + minWidth + "px;"; + } + + var i, length, option; + var renderIcon = false; + var icons = []; + var itemIcon; + for (i = 0, length = options.items.length; i < length; i++) { + + option = options.items[i]; + + itemIcon = option.icon || (option.selected ? 'check' : null); + + if (itemIcon) { + renderIcon = true; + } + icons.push(itemIcon || ''); + } + + if (layoutManager.tv) { + html += ''; + } + + // If any items have an icon, give them all an icon just to make sure they're all lined up evenly + var center = options.title && (!renderIcon /*|| itemsWithIcons.length != options.items.length*/); + + if (center || layoutManager.tv) { + html += '
'; + } else { + html += '
'; + } + + if (options.title) { + + html += '

'; + html += options.title; + html += '

'; + } + if (options.text) { + html += '

'; + html += options.text; + html += '

'; + } + + var scrollerClassName = 'actionSheetScroller'; + if (layoutManager.tv) { + scrollerClassName += ' actionSheetScroller-tv focuscontainer-x focuscontainer-y'; + } + html += '
'; + + var menuItemClass = 'listItem listItem-button actionSheetMenuItem'; + + if (options.border || options.shaded) { + menuItemClass += ' listItem-border'; + } + + if (options.menuItemClass) { + menuItemClass += ' ' + options.menuItemClass; + } + + if (layoutManager.tv) { + menuItemClass += ' listItem-focusscale'; + } + + if (layoutManager.mobile) { + menuItemClass += ' actionsheet-xlargeFont'; + } + + for (i = 0, length = options.items.length; i < length; i++) { + + option = options.items[i]; + + if (option.divider) { + + html += '
'; + continue; + } + + var autoFocus = option.selected && layoutManager.tv ? ' autoFocus' : ''; + + // Check for null in case int 0 was passed in + var optionId = option.id == null || option.id === '' ? option.value : option.id; + html += ''; + + itemIcon = icons[i]; + + if (itemIcon) { + + html += '' + itemIcon + ''; + } + else if (renderIcon && !center) { + html += ''; + } + + html += '
'; + + html += '
'; + html += (option.name || option.textContent || option.innerText); + html += '
'; + + if (option.secondaryText) { + html += '
'; + html += option.secondaryText; + html += '
'; + } + + html += '
'; + + if (option.asideText) { + html += '
'; + html += option.asideText; + html += '
'; + } + + html += ''; + } + + if (options.showCancel) { + html += '
'; + html += ''; + html += '
'; + } + html += '
'; + + dlg.innerHTML = html; + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.actionSheetScroller'), false, true); + } + + var btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet'); + if (btnCloseActionSheet) { + dlg.querySelector('.btnCloseActionSheet').addEventListener('click', function () { + dialogHelper.close(dlg); + }); + } + + // Seeing an issue in some non-chrome browsers where this is requiring a double click + //var eventName = browser.firefox ? 'mousedown' : 'click'; + var selectedId; + + var timeout; + if (options.timeout) { + timeout = setTimeout(function () { + dialogHelper.close(dlg); + }, options.timeout); + } + + return new Promise(function (resolve, reject) { + var isResolved; - dlg.addEventListener("click", function(e) { - var actionSheetMenuItem = dom.parentWithClass(e.target, "actionSheetMenuItem"); - actionSheetMenuItem && (selectedId = actionSheetMenuItem.getAttribute("data-id"), options.resolveOnClick && (options.resolveOnClick.indexOf ? -1 !== options.resolveOnClick.indexOf(selectedId) && (resolve(selectedId), isResolved = !0) : (resolve(selectedId), isResolved = !0)), dialogHelper.close(dlg)) - }), dlg.addEventListener("close", function() { - layoutManager.tv && centerFocus(dlg.querySelector(".actionSheetScroller"), !1, !1), timeout && (clearTimeout(timeout), timeout = null), isResolved || (null != selectedId ? (options.callback && options.callback(selectedId), resolve(selectedId)) : reject()) - }), dialogHelper.open(dlg); - var pos = options.positionTo && "fullscreen" !== dialogOptions.size ? getPosition(options, dlg) : null; - pos && (dlg.style.position = "fixed", dlg.style.margin = 0, dlg.style.left = pos.left + "px", dlg.style.top = pos.top + "px") - }) + + dlg.addEventListener('click', function (e) { + + var actionSheetMenuItem = dom.parentWithClass(e.target, 'actionSheetMenuItem'); + + if (actionSheetMenuItem) { + selectedId = actionSheetMenuItem.getAttribute('data-id'); + + if (options.resolveOnClick) { + + if (options.resolveOnClick.indexOf) { + + if (options.resolveOnClick.indexOf(selectedId) !== -1) { + + resolve(selectedId); + isResolved = true; + } + + } else { + resolve(selectedId); + isResolved = true; + } + } + + dialogHelper.close(dlg); + } + + }); + + dlg.addEventListener('close', function () { + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.actionSheetScroller'), false, false); + } + + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + + if (!isResolved) { + if (selectedId != null) { + if (options.callback) { + options.callback(selectedId); + } + + resolve(selectedId); + } else { + reject(); + } + } + }); + + dialogHelper.open(dlg); + + var pos = options.positionTo && dialogOptions.size !== 'fullscreen' ? getPosition(options, dlg) : null; + + if (pos) { + dlg.style.position = 'fixed'; + dlg.style.margin = 0; + dlg.style.left = pos.left + 'px'; + dlg.style.top = pos.top + 'px'; + } + }); } + return { show: show - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/alert/alert.js b/src/bower_components/emby-webcomponents/alert/alert.js index c9df6c23a3..83090c8d45 100644 --- a/src/bower_components/emby-webcomponents/alert/alert.js +++ b/src/bower_components/emby-webcomponents/alert/alert.js @@ -1,18 +1,34 @@ -define(["dialog", "globalize"], function(dialog, globalize) { - "use strict"; - return function(text, title) { +define(['dialog', 'globalize'], function (dialog, globalize) { + 'use strict'; + + return function (text, title) { + var options; - options = "string" == typeof text ? { - title: title, - text: text - } : text; + if (typeof text === 'string') { + options = { + title: title, + text: text + }; + } else { + options = text; + } + var items = []; - return items.push({ - name: globalize.translate("sharedcomponents#ButtonGotIt"), - id: "ok", - type: "submit" - }), options.buttons = items, dialog(options).then(function(result) { - return "ok" === result ? Promise.resolve() : Promise.reject() - }) - } + + items.push({ + name: globalize.translate('sharedcomponents#ButtonGotIt'), + id: 'ok', + type: 'submit' + }); + + options.buttons = items; + + return dialog(options).then(function (result) { + if (result === 'ok') { + return Promise.resolve(); + } + + return Promise.reject(); + }); + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/alert/nativealert.js b/src/bower_components/emby-webcomponents/alert/nativealert.js index 3d06cf10fe..f565e802c7 100644 --- a/src/bower_components/emby-webcomponents/alert/nativealert.js +++ b/src/bower_components/emby-webcomponents/alert/nativealert.js @@ -1,14 +1,23 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; function replaceAll(str, find, replace) { - return str.split(find).join(replace) - } - return function(options) { - "string" == typeof options && (options = { - text: options - }); - var text = replaceAll(options.text || "", "
", "\n"); - return alert(text), Promise.resolve() + + return str.split(find).join(replace); } + + return function (options) { + + if (typeof options === 'string') { + options = { + text: options + }; + } + + var text = replaceAll(options.text || '', '
', '\n'); + + alert(text); + + return Promise.resolve(); + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/alphanumericshortcuts/alphanumericshortcuts.js b/src/bower_components/emby-webcomponents/alphanumericshortcuts/alphanumericshortcuts.js index 2b4abe9e92..8517d1c3df 100644 --- a/src/bower_components/emby-webcomponents/alphanumericshortcuts/alphanumericshortcuts.js +++ b/src/bower_components/emby-webcomponents/alphanumericshortcuts/alphanumericshortcuts.js @@ -1,59 +1,130 @@ -define(["dom", "focusManager"], function(dom, focusManager) { - "use strict"; +define(['dom', 'focusManager'], function (dom, focusManager) { + 'use strict'; + + var inputDisplayElement; + var currentDisplayText = ''; + var currentDisplayTextContainer; function onKeyDown(e) { - if (!e.ctrlKey && !e.shiftKey && !e.altKey) { - var key = e.key, - chr = key ? alphanumeric(key) : null; - chr && (chr = chr.toString().toUpperCase(), 1 === chr.length && (currentDisplayTextContainer = this.options.itemsContainer, onAlphanumericKeyPress(e, chr))) + + if (e.ctrlKey) { + return; + } + if (!!e.shiftKey) { + return; + } + if (e.altKey) { + return; + } + + var key = e.key; + var chr = key ? alphanumeric(key) : null; + + if (chr) { + + chr = chr.toString().toUpperCase(); + + if (chr.length === 1) { + currentDisplayTextContainer = this.options.itemsContainer; + onAlphanumericKeyPress(e, chr); + } } } function alphanumeric(value) { var letterNumber = /^[0-9a-zA-Z]+$/; - return value.match(letterNumber) + return value.match(letterNumber); } function ensureInputDisplayElement() { - inputDisplayElement || (inputDisplayElement = document.createElement("div"), inputDisplayElement.classList.add("alphanumeric-shortcut"), inputDisplayElement.classList.add("hide"), document.body.appendChild(inputDisplayElement)) + if (!inputDisplayElement) { + inputDisplayElement = document.createElement('div'); + inputDisplayElement.classList.add('alphanumeric-shortcut'); + inputDisplayElement.classList.add('hide'); + + document.body.appendChild(inputDisplayElement); + } } + var alpanumericShortcutTimeout; function clearAlphaNumericShortcutTimeout() { - alpanumericShortcutTimeout && (clearTimeout(alpanumericShortcutTimeout), alpanumericShortcutTimeout = null) + if (alpanumericShortcutTimeout) { + clearTimeout(alpanumericShortcutTimeout); + alpanumericShortcutTimeout = null; + } } - function resetAlphaNumericShortcutTimeout() { - clearAlphaNumericShortcutTimeout(), alpanumericShortcutTimeout = setTimeout(onAlphanumericShortcutTimeout, 2e3) + clearAlphaNumericShortcutTimeout(); + alpanumericShortcutTimeout = setTimeout(onAlphanumericShortcutTimeout, 2000); } function onAlphanumericKeyPress(e, chr) { - currentDisplayText.length >= 3 || (ensureInputDisplayElement(), currentDisplayText += chr, inputDisplayElement.innerHTML = currentDisplayText, inputDisplayElement.classList.remove("hide"), resetAlphaNumericShortcutTimeout()) + if (currentDisplayText.length >= 3) { + return; + } + ensureInputDisplayElement(); + currentDisplayText += chr; + inputDisplayElement.innerHTML = currentDisplayText; + inputDisplayElement.classList.remove('hide'); + resetAlphaNumericShortcutTimeout(); } function onAlphanumericShortcutTimeout() { - var value = currentDisplayText, - container = currentDisplayTextContainer; - currentDisplayText = "", currentDisplayTextContainer = null, inputDisplayElement.innerHTML = "", inputDisplayElement.classList.add("hide"), clearAlphaNumericShortcutTimeout(), selectByShortcutValue(container, value) + var value = currentDisplayText; + var container = currentDisplayTextContainer; + + currentDisplayText = ''; + currentDisplayTextContainer = null; + inputDisplayElement.innerHTML = ''; + inputDisplayElement.classList.add('hide'); + clearAlphaNumericShortcutTimeout(); + selectByShortcutValue(container, value); } function selectByShortcutValue(container, value) { + value = value.toUpperCase(); + var focusElem; - "#" === value && (focusElem = container.querySelector("*[data-prefix]")), focusElem || (focusElem = container.querySelector("*[data-prefix^='" + value + "']")), focusElem && focusManager.focus(focusElem) + if (value === '#') { + + focusElem = container.querySelector('*[data-prefix]'); + } + + if (!focusElem) { + focusElem = container.querySelector('*[data-prefix^=\'' + value + '\']'); + } + + if (focusElem) { + focusManager.focus(focusElem); + } } function AlphaNumericShortcuts(options) { + this.options = options; + var keyDownHandler = onKeyDown.bind(this); - dom.addEventListener(window, "keydown", keyDownHandler, { - passive: !0 - }), this.keyDownHandler = keyDownHandler + + dom.addEventListener(window, 'keydown', keyDownHandler, { + passive: true + }); + + this.keyDownHandler = keyDownHandler; } - var inputDisplayElement, currentDisplayTextContainer, alpanumericShortcutTimeout, currentDisplayText = ""; - return AlphaNumericShortcuts.prototype.destroy = function() { + + AlphaNumericShortcuts.prototype.destroy = function () { + var keyDownHandler = this.keyDownHandler; - keyDownHandler && (dom.removeEventListener(window, "keydown", keyDownHandler, { - passive: !0 - }), this.keyDownHandler = null), this.options = null - }, AlphaNumericShortcuts + + if (keyDownHandler) { + dom.removeEventListener(window, 'keydown', keyDownHandler, { + passive: true + }); + this.keyDownHandler = null; + } + this.options = null; + }; + + return AlphaNumericShortcuts; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/alphapicker/alphapicker.js b/src/bower_components/emby-webcomponents/alphapicker/alphapicker.js index 1d7fabb6f8..4cf77f451a 100644 --- a/src/bower_components/emby-webcomponents/alphapicker/alphapicker.js +++ b/src/bower_components/emby-webcomponents/alphapicker/alphapicker.js @@ -1,127 +1,324 @@ -define(["focusManager", "layoutManager", "dom", "css!./style.css", "paper-icon-button-light", "material-icons"], function(focusManager, layoutManager, dom) { - "use strict"; +define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-button-light', 'material-icons'], function (focusManager, layoutManager, dom) { + 'use strict'; + + var selectedButtonClass = 'alphaPickerButton-selected'; function focus() { - var scope = this, - selected = scope.querySelector("." + selectedButtonClass); - selected ? focusManager.focus(selected) : focusManager.autoFocus(scope, !0) + var scope = this; + var selected = scope.querySelector('.' + selectedButtonClass); + + if (selected) { + focusManager.focus(selected); + } else { + focusManager.autoFocus(scope, true); + } } function getAlphaPickerButtonClassName(vertical) { - var alphaPickerButtonClassName = "alphaPickerButton"; - return layoutManager.tv && (alphaPickerButtonClassName += " alphaPickerButton-tv"), vertical && (alphaPickerButtonClassName += " alphaPickerButton-vertical"), alphaPickerButtonClassName + + var alphaPickerButtonClassName = 'alphaPickerButton'; + + if (layoutManager.tv) { + alphaPickerButtonClassName += ' alphaPickerButton-tv'; + } + + if (vertical) { + alphaPickerButtonClassName += ' alphaPickerButton-vertical'; + } + + return alphaPickerButtonClassName; } function getLetterButton(l, vertical) { - return '" + return ''; } function mapLetters(letters, vertical) { - return letters.map(function(l) { - return getLetterButton(l, vertical) - }) + + return letters.map(function (l) { + return getLetterButton(l, vertical); + }); } function render(element, options) { - element.classList.add("alphaPicker"), layoutManager.tv && element.classList.add("alphaPicker-tv"); - var vertical = element.classList.contains("alphaPicker-vertical"); - vertical || element.classList.add("focuscontainer-x"); - var letters, html = "", - alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical), - rowClassName = "alphaPickerRow"; - vertical && (rowClassName += " alphaPickerRow-vertical"), html += '
', "keyboard" === options.mode ? html += '' : (letters = ["#"], html += mapLetters(letters, vertical).join("")), letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"], html += mapLetters(letters, vertical).join(""), "keyboard" === options.mode ? (html += '', html += "
", letters = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], html += '
', html += "
", html += mapLetters(letters, vertical).join(""), html += "
") : html += "
", element.innerHTML = html, element.classList.add("focusable"), element.focus = focus + + element.classList.add('alphaPicker'); + + if (layoutManager.tv) { + element.classList.add('alphaPicker-tv'); + } + + var vertical = element.classList.contains('alphaPicker-vertical'); + + if (vertical) { + + } else { + element.classList.add('focuscontainer-x'); + } + + var html = ''; + var letters; + + var alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical); + + var rowClassName = 'alphaPickerRow'; + + if (vertical) { + rowClassName += ' alphaPickerRow-vertical'; + } + + html += '
'; + if (options.mode === 'keyboard') { + // space_bar icon + html += ''; + } else { + letters = ['#']; + html += mapLetters(letters, vertical).join(''); + } + + letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; + html += mapLetters(letters, vertical).join(''); + + if (options.mode === 'keyboard') { + // backspace icon + html += ''; + html += '
'; + + letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + html += '
'; + html += '
'; + html += mapLetters(letters, vertical).join(''); + html += '
'; + } else { + html += '
'; + } + + element.innerHTML = html; + + element.classList.add('focusable'); + element.focus = focus; } function AlphaPicker(options) { + + var self = this; + this.options = options; + + var element = options.element; + var itemsContainer = options.itemsContainer; + var itemClass = options.itemClass; + + var itemFocusValue; + var itemFocusTimeout; + function onItemFocusTimeout() { - itemFocusTimeout = null, self.value(itemFocusValue) + itemFocusTimeout = null; + self.value(itemFocusValue); } + var alphaFocusedElement; + var alphaFocusTimeout; + function onAlphaFocusTimeout() { - if (alphaFocusTimeout = null, document.activeElement === alphaFocusedElement) { - var value = alphaFocusedElement.getAttribute("data-value"); - self.value(value, !0) + + alphaFocusTimeout = null; + + if (document.activeElement === alphaFocusedElement) { + var value = alphaFocusedElement.getAttribute('data-value'); + self.value(value, true); } } function onAlphaPickerInKeyboardModeClick(e) { - var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton"); + + var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton'); + if (alphaPickerButton) { - var value = alphaPickerButton.getAttribute("data-value"); + var value = alphaPickerButton.getAttribute('data-value'); + element.dispatchEvent(new CustomEvent("alphavalueclicked", { - cancelable: !1, + cancelable: false, detail: { value: value } - })) + })); } } function onAlphaPickerClick(e) { - var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton"); + + var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton'); + if (alphaPickerButton) { - var value = alphaPickerButton.getAttribute("data-value"); - (this._currentValue || "").toUpperCase() === value.toUpperCase() ? self.value(null, !0) : self.value(value, !0) + var value = alphaPickerButton.getAttribute('data-value'); + if ((this._currentValue || '').toUpperCase() === value.toUpperCase()) { + self.value(null, true); + } else { + self.value(value, true); + } } } function onAlphaPickerFocusIn(e) { - alphaFocusTimeout && (clearTimeout(alphaFocusTimeout), alphaFocusTimeout = null); - var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton"); - alphaPickerButton && (alphaFocusedElement = alphaPickerButton, alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600)) + + if (alphaFocusTimeout) { + clearTimeout(alphaFocusTimeout); + alphaFocusTimeout = null; + } + + var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton'); + + if (alphaPickerButton) { + alphaFocusedElement = alphaPickerButton; + alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600); + } } function onItemsFocusIn(e) { + var item = dom.parentWithClass(e.target, itemClass); + if (item) { - var prefix = item.getAttribute("data-prefix"); - prefix && prefix.length && (itemFocusValue = prefix[0], itemFocusTimeout && clearTimeout(itemFocusTimeout), itemFocusTimeout = setTimeout(onItemFocusTimeout, 100)) + var prefix = item.getAttribute('data-prefix'); + if (prefix && prefix.length) { + + itemFocusValue = prefix[0]; + if (itemFocusTimeout) { + clearTimeout(itemFocusTimeout); + } + itemFocusTimeout = setTimeout(onItemFocusTimeout, 100); + } } } - var self = this; - this.options = options; - var itemFocusValue, itemFocusTimeout, alphaFocusedElement, alphaFocusTimeout, element = options.element, - itemsContainer = options.itemsContainer, - itemClass = options.itemClass; - self.enabled = function(enabled) { - enabled ? (itemsContainer && itemsContainer.addEventListener("focus", onItemsFocusIn, !0), "keyboard" === options.mode && element.addEventListener("click", onAlphaPickerInKeyboardModeClick), "click" !== options.valueChangeEvent ? element.addEventListener("focus", onAlphaPickerFocusIn, !0) : element.addEventListener("click", onAlphaPickerClick.bind(this))) : (itemsContainer && itemsContainer.removeEventListener("focus", onItemsFocusIn, !0), element.removeEventListener("click", onAlphaPickerInKeyboardModeClick), element.removeEventListener("focus", onAlphaPickerFocusIn, !0), element.removeEventListener("click", onAlphaPickerClick.bind(this))) - }, render(element, options), this.enabled(!0), this.visible(!0) - } - var selectedButtonClass = "alphaPickerButton-selected"; - return AlphaPicker.prototype.value = function(value, applyValue) { - var btn, selected, element = this.options.element; - if (void 0 !== value) - if (null != value) { - if (value = value.toUpperCase(), this._currentValue = value, "keyboard" !== this.options.mode) { - selected = element.querySelector("." + selectedButtonClass); - try { - btn = element.querySelector(".alphaPickerButton[data-value='" + value + "']") - } catch (err) { - console.log("Error in querySelector: " + err) - } - btn && btn !== selected && btn.classList.add(selectedButtonClass), selected && selected !== btn && selected.classList.remove(selectedButtonClass) + + self.enabled = function (enabled) { + + if (enabled) { + + if (itemsContainer) { + itemsContainer.addEventListener('focus', onItemsFocusIn, true); } - } else this._currentValue = value, (selected = element.querySelector("." + selectedButtonClass)) && selected.classList.remove(selectedButtonClass); - return applyValue && element.dispatchEvent(new CustomEvent("alphavaluechanged", { - cancelable: !1, - detail: { - value: value + + if (options.mode === 'keyboard') { + element.addEventListener('click', onAlphaPickerInKeyboardModeClick); + } + + if (options.valueChangeEvent !== 'click') { + element.addEventListener('focus', onAlphaPickerFocusIn, true); + } else { + element.addEventListener('click', onAlphaPickerClick.bind(this)); + } + + } else { + + if (itemsContainer) { + itemsContainer.removeEventListener('focus', onItemsFocusIn, true); + } + + element.removeEventListener('click', onAlphaPickerInKeyboardModeClick); + element.removeEventListener('focus', onAlphaPickerFocusIn, true); + element.removeEventListener('click', onAlphaPickerClick.bind(this)); } - })), this._currentValue - }, AlphaPicker.prototype.on = function(name, fn) { - this.options.element.addEventListener(name, fn) - }, AlphaPicker.prototype.off = function(name, fn) { - this.options.element.removeEventListener(name, fn) - }, AlphaPicker.prototype.visible = function(visible) { - this.options.element.style.visibility = visible ? "visible" : "hidden" - }, AlphaPicker.prototype.values = function() { - for (var element = this.options.element, elems = element.querySelectorAll(".alphaPickerButton"), values = [], i = 0, length = elems.length; i < length; i++) values.push(elems[i].getAttribute("data-value")); - return values - }, AlphaPicker.prototype.focus = function() { + }; + + render(element, options); + + this.enabled(true); + this.visible(true); + } + + AlphaPicker.prototype.value = function (value, applyValue) { + var element = this.options.element; - focusManager.autoFocus(element, !0) - }, AlphaPicker.prototype.destroy = function() { + var btn, selected; + + if (value !== undefined) { + if (value != null) { + + value = value.toUpperCase(); + this._currentValue = value; + + if (this.options.mode !== 'keyboard') { + selected = element.querySelector('.' + selectedButtonClass); + + try { + btn = element.querySelector('.alphaPickerButton[data-value=\'' + value + '\']'); + } catch (err) { + console.log('Error in querySelector: ' + err); + } + + if (btn && btn !== selected) { + btn.classList.add(selectedButtonClass); + } + if (selected && selected !== btn) { + selected.classList.remove(selectedButtonClass); + } + } + } else { + this._currentValue = value; + + selected = element.querySelector('.' + selectedButtonClass); + if (selected) { + selected.classList.remove(selectedButtonClass); + } + } + } + + if (applyValue) { + element.dispatchEvent(new CustomEvent("alphavaluechanged", { + cancelable: false, + detail: { + value: value + } + })); + } + + return this._currentValue; + }; + + AlphaPicker.prototype.on = function (name, fn) { var element = this.options.element; - this.enabled(!1), element.classList.remove("focuscontainer-x"), this.options = null - }, AlphaPicker + element.addEventListener(name, fn); + }; + + AlphaPicker.prototype.off = function (name, fn) { + var element = this.options.element; + element.removeEventListener(name, fn); + }; + + AlphaPicker.prototype.visible = function (visible) { + + var element = this.options.element; + element.style.visibility = visible ? 'visible' : 'hidden'; + }; + + AlphaPicker.prototype.values = function () { + + var element = this.options.element; + var elems = element.querySelectorAll('.alphaPickerButton'); + var values = []; + for (var i = 0, length = elems.length; i < length; i++) { + + values.push(elems[i].getAttribute('data-value')); + + } + + return values; + }; + + AlphaPicker.prototype.focus = function () { + + var element = this.options.element; + focusManager.autoFocus(element, true); + }; + + AlphaPicker.prototype.destroy = function () { + + var element = this.options.element; + this.enabled(false); + element.classList.remove('focuscontainer-x'); + this.options = null; + }; + + return AlphaPicker; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/alphapicker/style.css b/src/bower_components/emby-webcomponents/alphapicker/style.css index 6c366e8113..29543421eb 100644 --- a/src/bower_components/emby-webcomponents/alphapicker/style.css +++ b/src/bower_components/emby-webcomponents/alphapicker/style.css @@ -1,59 +1,35 @@ -.alphaPicker, -.alphaPickerRow { - display: -webkit-box; - display: -webkit-flex; - -webkit-box-direction: normal -} - -.alphaPicker, -.alphaPickerRow, -.alphaPickerRow-vertical { - -webkit-box-direction: normal -} - .alphaPicker { text-align: center; display: flex; - -webkit-box-orient: vertical; - -webkit-flex-direction: column; flex-direction: column; - -webkit-align-self: center; - align-self: center + align-self: center; } .alphaPicker-vertical { - line-height: 1 + line-height: 1; } .alphaPicker-fixed { position: fixed; bottom: 5.5em; - z-index: 999999 + z-index: 999999; } .alphaPickerRow { display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; - -webkit-box-orient: horizontal; - -webkit-flex-direction: row; - flex-direction: row + flex-direction: row; } .alphaPickerRow-vertical { - -webkit-box-orient: vertical; - -webkit-flex-direction: column; - flex-direction: column + flex-direction: column; } .alphaPickerButton { border: 0 !important; cursor: pointer; - outline: 0 !important; + outline: none !important; vertical-align: middle; font-family: inherit; font-size: inherit; @@ -61,103 +37,103 @@ margin: 0; padding: .1em .4em; width: auto; - -webkit-border-radius: .1em; border-radius: .1em; - font-weight: 400; - -webkit-flex-shrink: 0; + font-weight: normal; flex-shrink: 0; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - flex-grow: 1 + flex-grow: 1; } -@media all and (max-height:50em) { +@media all and (max-height: 50em) { + .alphaPicker-fixed { - bottom: 5em + bottom: 5em; } .alphaPickerButton-vertical { padding-top: 1px !important; - padding-bottom: 1px !important + padding-bottom: 1px !important; } } -@media all and (max-height:49em) { +@media all and (max-height: 49em) { + .alphaPicker-vertical { - font-size: 94% + font-size: 94%; } } -@media all and (max-height:44em) { +@media all and (max-height: 44em) { + .alphaPicker-vertical { - font-size: 90% + font-size: 90%; } .alphaPickerButton-vertical { padding-top: 0 !important; - padding-bottom: 0 !important + padding-bottom: 0 !important; } } -@media all and (max-height:37em) { +@media all and (max-height: 37em) { + .alphaPicker-vertical { - font-size: 82% + font-size: 82%; } } -@media all and (max-height:32em) { +@media all and (max-height: 32em) { + .alphaPicker-vertical { - font-size: 74% + font-size: 74%; } } .alphaPicker-vertical.alphaPicker-tv { - font-size: 86% + font-size: 86%; } .alphaPickerButton-tv.alphaPickerButton-vertical { - padding: 0 + padding: 0; } .alphaPickerButton-vertical { + /* Assign a fixed width to ensure they have the same dimensions and avoid throwing off directional navigation */ width: 1.5em; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; - text-align: center + text-align: center; } .alphaPickerButtonIcon { - font-size: 100% !important + font-size: 100% !important; } .alphaPicker-fixed.alphaPicker-tv { - bottom: 1% + bottom: 1%; } .alphaPicker-fixed-left { - left: .4em + left: .4em; } .alphaPicker-fixed-right { - right: .4em + right: .4em; } -@media all and (min-width:62.5em) { +@media all and (min-width: 62.5em) { + .alphaPicker-fixed-left { - left: 1em + left: 1em; } .alphaPicker-fixed-right { - right: 1em + right: 1em; } } -@media all and (max-height:31.25em) { +@media all and (max-height: 31.25em) { + .alphaPicker-fixed { - display: none !important + display: none !important; } -} \ No newline at end of file +} diff --git a/src/bower_components/emby-webcomponents/appfooter/appfooter.css b/src/bower_components/emby-webcomponents/appfooter/appfooter.css index 7a97db76df..320d34a4a9 100644 --- a/src/bower_components/emby-webcomponents/appfooter/appfooter.css +++ b/src/bower_components/emby-webcomponents/appfooter/appfooter.css @@ -1,16 +1,13 @@ -.appfooter { +.appfooter { position: fixed; left: 0; right: 0; z-index: 1; bottom: 0; - -webkit-transition: -webkit-transform 180ms linear; - -o-transition: transform 180ms linear; transition: transform 180ms linear; - contain: layout style + contain: layout style; } -.appfooter.headroom--unpinned { - -webkit-transform: translateY(100%) !important; - transform: translateY(100%) !important -} \ No newline at end of file + .appfooter.headroom--unpinned { + transform: translateY(100%)!important; + } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/appfooter/appfooter.js b/src/bower_components/emby-webcomponents/appfooter/appfooter.js index e9dbffe0bb..3f69efc573 100644 --- a/src/bower_components/emby-webcomponents/appfooter/appfooter.js +++ b/src/bower_components/emby-webcomponents/appfooter/appfooter.js @@ -1,20 +1,46 @@ -define(["browser", "css!./appfooter"], function(browser) { - "use strict"; +define(['browser', 'css!./appfooter'], function (browser) { + 'use strict'; function render(options) { - var elem = document.createElement("div"); - return elem.classList.add("appfooter"), browser.chrome || elem.classList.add("appfooter-blurred"), document.body.appendChild(elem), elem + + var elem = document.createElement('div'); + + elem.classList.add('appfooter'); + + if (!browser.chrome) { + // chrome does not display this properly + elem.classList.add('appfooter-blurred'); + } + + document.body.appendChild(elem); + + return elem; } function appFooter(options) { + var self = this; - self.element = render(options), self.add = function(elem) { - self.element.appendChild(elem) - }, self.insert = function(elem) { - "string" == typeof elem ? self.element.insertAdjacentHTML("afterbegin", elem) : self.element.insertBefore(elem, self.element.firstChild) - } + + self.element = render(options); + + self.add = function (elem) { + self.element.appendChild(elem); + }; + + self.insert = function (elem) { + if (typeof elem === 'string') { + self.element.insertAdjacentHTML('afterbegin', elem); + } else { + self.element.insertBefore(elem, self.element.firstChild); + } + }; } - return appFooter.prototype.destroy = function() { - this.element = null - }, appFooter + + appFooter.prototype.destroy = function () { + var self = this; + + self.element = null; + }; + + return appFooter; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/appsettings.js b/src/bower_components/emby-webcomponents/appsettings.js index 722bdf2aec..3fd2b33183 100644 --- a/src/bower_components/emby-webcomponents/appsettings.js +++ b/src/bower_components/emby-webcomponents/appsettings.js @@ -1,39 +1,156 @@ -define(["appStorage", "events"], function(appStorage, events) { - "use strict"; +define(['appStorage', 'events'], function (appStorage, events) { + 'use strict'; function getKey(name, userId) { - return userId && (name = userId + "-" + name), name + + if (userId) { + name = userId + '-' + name; + } + + return name; } - function AppSettings() {} - return AppSettings.prototype.enableAutoLogin = function(val) { - return null != val && this.set("enableAutoLogin", val.toString()), "false" !== this.get("enableAutoLogin") - }, AppSettings.prototype.enableAutomaticBitrateDetection = function(isInNetwork, mediaType, val) { - var key = "enableautobitratebitrate-" + mediaType + "-" + isInNetwork; - return null != val && (isInNetwork && "Audio" === mediaType && (val = !0), this.set(key, val.toString())), !(!isInNetwork || "Audio" !== mediaType) || "false" !== this.get(key) - }, AppSettings.prototype.maxStreamingBitrate = function(isInNetwork, mediaType, val) { - var key = "maxbitrate-" + mediaType + "-" + isInNetwork; - return null != val && (isInNetwork && "Audio" === mediaType || this.set(key, val)), isInNetwork && "Audio" === mediaType ? 15e7 : parseInt(this.get(key) || "0") || 15e5 - }, AppSettings.prototype.maxStaticMusicBitrate = function(val) { - void 0 !== val && this.set("maxStaticMusicBitrate", val); - var defaultValue = 32e4; - return parseInt(this.get("maxStaticMusicBitrate") || defaultValue.toString()) || defaultValue - }, AppSettings.prototype.maxChromecastBitrate = function(val) { - return null != val && this.set("chromecastBitrate1", val), val = this.get("chromecastBitrate1"), val ? parseInt(val) : null - }, AppSettings.prototype.syncOnlyOnWifi = function(val) { - return null != val && this.set("syncOnlyOnWifi", val.toString()), "false" !== this.get("syncOnlyOnWifi") - }, AppSettings.prototype.syncPath = function(val) { - return null != val && this.set("syncPath", val), this.get("syncPath") - }, AppSettings.prototype.cameraUploadServers = function(val) { - return null != val && this.set("cameraUploadServers", val.join(",")), val = this.get("cameraUploadServers"), val ? val.split(",") : [] - }, AppSettings.prototype.runAtStartup = function(val) { - return null != val && this.set("runatstartup", val.toString()), "true" === this.get("runatstartup") - }, AppSettings.prototype.set = function(name, value, userId) { + function AppSettings() { + + } + + AppSettings.prototype.enableAutoLogin = function (val) { + + if (val != null) { + this.set('enableAutoLogin', val.toString()); + } + + return this.get('enableAutoLogin') !== 'false'; + }; + + AppSettings.prototype.enableAutomaticBitrateDetection = function (isInNetwork, mediaType, val) { + + var key = 'enableautobitratebitrate-' + mediaType + '-' + isInNetwork; + + if (val != null) { + + if (isInNetwork && mediaType === 'Audio') { + val = true; + } + + this.set(key, val.toString()); + } + + if (isInNetwork && mediaType === 'Audio') { + return true; + } else { + return this.get(key) !== 'false'; + } + }; + + AppSettings.prototype.maxStreamingBitrate = function (isInNetwork, mediaType, val) { + + var key = 'maxbitrate-' + mediaType + '-' + isInNetwork; + + if (val != null) { + + if (isInNetwork && mediaType === 'Audio') { + // nothing to do, this is always a max value + } else { + this.set(key, val); + } + } + + if (isInNetwork && mediaType === 'Audio') { + // return a huge number so that it always direct plays + return 150000000; + } else { + return parseInt(this.get(key) || '0') || 1500000; + } + }; + + AppSettings.prototype.maxStaticMusicBitrate = function (val) { + + if (val !== undefined) { + this.set('maxStaticMusicBitrate', val); + } + + var defaultValue = 320000; + return parseInt(this.get('maxStaticMusicBitrate') || defaultValue.toString()) || defaultValue; + }; + + AppSettings.prototype.maxChromecastBitrate = function (val) { + + if (val != null) { + this.set('chromecastBitrate1', val); + } + + val = this.get('chromecastBitrate1'); + + return val ? parseInt(val) : null; + }; + + AppSettings.prototype.syncOnlyOnWifi = function (val) { + + if (val != null) { + this.set('syncOnlyOnWifi', val.toString()); + } + + return this.get('syncOnlyOnWifi') !== 'false'; + }; + + AppSettings.prototype.syncPath = function (val) { + + if (val != null) { + this.set('syncPath', val); + } + + return this.get('syncPath'); + }; + + AppSettings.prototype.cameraUploadServers = function (val) { + + if (val != null) { + this.set('cameraUploadServers', val.join(',')); + } + + val = this.get('cameraUploadServers'); + + if (val) { + return val.split(','); + } + + return []; + }; + + AppSettings.prototype.runAtStartup = function (val) { + + if (val != null) { + this.set('runatstartup', val.toString()); + } + + return this.get('runatstartup') === 'true'; + }; + + AppSettings.prototype.set = function (name, value, userId) { + var currentValue = this.get(name, userId); - appStorage.setItem(getKey(name, userId), value), currentValue !== value && events.trigger(this, "change", [name]) - }, AppSettings.prototype.get = function(name, userId) { - return appStorage.getItem(getKey(name, userId)) - }, AppSettings.prototype.enableSystemExternalPlayers = function(val) { - return null != val && this.set("enableSystemExternalPlayers", val.toString()), "true" === this.get("enableSystemExternalPlayers") - }, new AppSettings + + appStorage.setItem(getKey(name, userId), value); + + if (currentValue !== value) { + events.trigger(this, 'change', [name]); + } + }; + + AppSettings.prototype.get = function (name, userId) { + + return appStorage.getItem(getKey(name, userId)); + }; + + AppSettings.prototype.enableSystemExternalPlayers = function (val) { + + if (val != null) { + this.set('enableSystemExternalPlayers', val.toString()); + } + + return this.get('enableSystemExternalPlayers') === 'true'; + }; + + return new AppSettings(); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/backdrop/backdrop.js b/src/bower_components/emby-webcomponents/backdrop/backdrop.js index 2f42ccd347..12a077c68c 100644 --- a/src/bower_components/emby-webcomponents/backdrop/backdrop.js +++ b/src/bower_components/emby-webcomponents/backdrop/backdrop.js @@ -1,150 +1,358 @@ -define(["browser", "connectionManager", "playbackManager", "dom", "css!./style"], function(browser, connectionManager, playbackManager, dom) { - "use strict"; +define(['browser', 'connectionManager', 'playbackManager', 'dom', 'css!./style'], function (browser, connectionManager, playbackManager, dom) { + 'use strict'; function enableAnimation(elem) { - return !browser.slow + + if (browser.slow) { + return false; + } + + return true; } function enableRotation() { - return !browser.tv && !browser.firefox + + if (browser.tv) { + return false; + } + + // Causes high cpu usage + if (browser.firefox) { + return false; + } + + return true; } - function Backdrop() {} + function Backdrop() { + } + + Backdrop.prototype.load = function (url, parent, existingBackdropImage) { + + var img = new Image(); + + var self = this; + + img.onload = function () { + + if (self.isDestroyed) { + return; + } + + var backdropImage = document.createElement('div'); + backdropImage.classList.add('backdropImage'); + backdropImage.classList.add('displayingBackdropImage'); + backdropImage.style.backgroundImage = "url('" + url + "')"; + backdropImage.setAttribute('data-url', url); + + backdropImage.classList.add('backdropImageFadeIn'); + parent.appendChild(backdropImage); + + if (!enableAnimation(backdropImage)) { + if (existingBackdropImage && existingBackdropImage.parentNode) { + existingBackdropImage.parentNode.removeChild(existingBackdropImage); + } + internalBackdrop(true); + return; + } + + var onAnimationComplete = function () { + dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, { + once: true + }); + if (backdropImage === self.currentAnimatingElement) { + self.currentAnimatingElement = null; + } + if (existingBackdropImage && existingBackdropImage.parentNode) { + existingBackdropImage.parentNode.removeChild(existingBackdropImage); + } + }; + + dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, { + once: true + }); + + internalBackdrop(true); + }; + img.src = url; + }; + + Backdrop.prototype.cancelAnimation = function () { + var elem = this.currentAnimatingElement; + if (elem) { + elem.classList.remove('backdropImageFadeIn'); + this.currentAnimatingElement = null; + } + }; + + Backdrop.prototype.destroy = function () { + + this.isDestroyed = true; + this.cancelAnimation(); + }; + + var backdropContainer; function getBackdropContainer() { - return backdropContainer || (backdropContainer = document.querySelector(".backdropContainer")), backdropContainer || (backdropContainer = document.createElement("div"), backdropContainer.classList.add("backdropContainer"), document.body.insertBefore(backdropContainer, document.body.firstChild)), backdropContainer + + if (!backdropContainer) { + backdropContainer = document.querySelector('.backdropContainer'); + } + + if (!backdropContainer) { + backdropContainer = document.createElement('div'); + backdropContainer.classList.add('backdropContainer'); + document.body.insertBefore(backdropContainer, document.body.firstChild); + } + + return backdropContainer; } function clearBackdrop(clearAll) { - clearRotation(), currentLoadingBackdrop && (currentLoadingBackdrop.destroy(), currentLoadingBackdrop = null), getBackdropContainer().innerHTML = "", clearAll && (hasExternalBackdrop = !1), internalBackdrop(!1) - } - function getBackgroundContainer() { - return backgroundContainer || (backgroundContainer = document.querySelector(".backgroundContainer")), backgroundContainer - } + clearRotation(); - function setBackgroundContainerBackgroundEnabled() { - hasInternalBackdrop || hasExternalBackdrop ? getBackgroundContainer().classList.add("withBackdrop") : getBackgroundContainer().classList.remove("withBackdrop") - } - - function internalBackdrop(enabled) { - hasInternalBackdrop = enabled, setBackgroundContainerBackgroundEnabled() - } - - function externalBackdrop(enabled) { - hasExternalBackdrop = enabled, setBackgroundContainerBackgroundEnabled() - } - - function setBackdropImage(url) { - currentLoadingBackdrop && (currentLoadingBackdrop.destroy(), currentLoadingBackdrop = null); - var elem = getBackdropContainer(), - existingBackdropImage = elem.querySelector(".displayingBackdropImage"); - if (existingBackdropImage && existingBackdropImage.getAttribute("data-url") === url) { - if (existingBackdropImage.getAttribute("data-url") === url) return; - existingBackdropImage.classList.remove("displayingBackdropImage") + if (currentLoadingBackdrop) { + currentLoadingBackdrop.destroy(); + currentLoadingBackdrop = null; } - var instance = new Backdrop; - instance.load(url, elem, existingBackdropImage), currentLoadingBackdrop = instance + + var elem = getBackdropContainer(); + elem.innerHTML = ''; + + if (clearAll) { + hasExternalBackdrop = false; + } + internalBackdrop(false); } + var backgroundContainer; + function getBackgroundContainer() { + if (!backgroundContainer) { + backgroundContainer = document.querySelector('.backgroundContainer'); + } + return backgroundContainer; + } + function setBackgroundContainerBackgroundEnabled() { + + if (hasInternalBackdrop || hasExternalBackdrop) { + getBackgroundContainer().classList.add('withBackdrop'); + } else { + getBackgroundContainer().classList.remove('withBackdrop'); + } + } + + var hasInternalBackdrop; + function internalBackdrop(enabled) { + hasInternalBackdrop = enabled; + setBackgroundContainerBackgroundEnabled(); + } + + var hasExternalBackdrop; + function externalBackdrop(enabled) { + hasExternalBackdrop = enabled; + setBackgroundContainerBackgroundEnabled(); + } + + function getRandom(min, max) { + return Math.floor(Math.random() * (max - min) + min); + } + + var currentLoadingBackdrop; + function setBackdropImage(url) { + + if (currentLoadingBackdrop) { + currentLoadingBackdrop.destroy(); + currentLoadingBackdrop = null; + } + + var elem = getBackdropContainer(); + var existingBackdropImage = elem.querySelector('.displayingBackdropImage'); + + if (existingBackdropImage && existingBackdropImage.getAttribute('data-url') === url) { + if (existingBackdropImage.getAttribute('data-url') === url) { + return; + } + existingBackdropImage.classList.remove('displayingBackdropImage'); + } + + var instance = new Backdrop(); + instance.load(url, elem, existingBackdropImage); + currentLoadingBackdrop = instance; + } + + var standardWidths = [480, 720, 1280, 1440, 1920]; function getBackdropMaxWidth() { + var width = dom.getWindowSize().innerWidth; - if (-1 !== standardWidths.indexOf(width)) return width; - return width = 100 * Math.floor(width / 100), Math.min(width, 1920) + + 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); - return item.BackdropImageTags && item.BackdropImageTags.length > 0 ? item.BackdropImageTags.map(function(imgTag, index) { - return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, { - type: "Backdrop", - tag: imgTag, - maxWidth: getBackdropMaxWidth(), - index: index - })) - }) : item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length ? item.ParentBackdropImageTags.map(function(imgTag, index) { - return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, { - type: "Backdrop", - tag: imgTag, - maxWidth: getBackdropMaxWidth(), - index: index - })) - }) : [] + + if (item.BackdropImageTags && item.BackdropImageTags.length > 0) { + + return item.BackdropImageTags.map(function (imgTag, index) { + + return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, { + type: "Backdrop", + tag: imgTag, + maxWidth: getBackdropMaxWidth(), + index: index + })); + }); + } + + if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { + + return item.ParentBackdropImageTags.map(function (imgTag, index) { + + return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, { + type: "Backdrop", + tag: imgTag, + maxWidth: getBackdropMaxWidth(), + index: index + })); + }); + } + + return []; } function getImageUrls(items, imageOptions) { - for (var list = [], onImg = function(img) { - list.push(img) - }, i = 0, length = items.length; i < length; i++) { - getItemImageUrls(items[i], imageOptions).forEach(onImg) + + var list = []; + + var onImg = function (img) { + list.push(img); + }; + + for (var i = 0, length = items.length; i < length; i++) { + + var itemImages = getItemImageUrls(items[i], imageOptions); + + itemImages.forEach(onImg); } - return list + + return list; } function arraysEqual(a, b) { - if (a === b) return !0; - if (null == a || null == b) return !1; - if (a.length !== b.length) return !1; - for (var i = 0; i < a.length; ++i) - if (a[i] !== b[i]) return !1; - return !0 + if (a === b) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a.length !== b.length) { + return false; + } + + // If you don't care about the order of the elements inside + // the array, you should sort both arrays here. + + for (var i = 0; i < a.length; ++i) { + if (a[i] !== b[i]) { + return false; + } + } + return true; } + var rotationInterval; + var currentRotatingImages = []; + var currentRotationIndex = -1; function setBackdrops(items, imageOptions, enableImageRotation) { + var images = getImageUrls(items, imageOptions); - images.length ? startRotation(images, enableImageRotation) : clearBackdrop() + + if (images.length) { + + startRotation(images, enableImageRotation); + + } else { + clearBackdrop(); + } } function startRotation(images, enableImageRotation) { - arraysEqual(images, currentRotatingImages) || (clearRotation(), currentRotatingImages = images, currentRotationIndex = -1, images.length > 1 && !1 !== enableImageRotation && enableRotation() && (rotationInterval = setInterval(onRotationInterval, 24e3)), onRotationInterval()) + + if (arraysEqual(images, currentRotatingImages)) { + return; + } + + clearRotation(); + + currentRotatingImages = images; + currentRotationIndex = -1; + + if (images.length > 1 && enableImageRotation !== false && enableRotation()) { + rotationInterval = setInterval(onRotationInterval, 24000); + } + onRotationInterval(); } function onRotationInterval() { - if (!playbackManager.isPlayingLocally(["Video"])) { - var newIndex = currentRotationIndex + 1; - newIndex >= currentRotatingImages.length && (newIndex = 0), currentRotationIndex = newIndex, setBackdropImage(currentRotatingImages[newIndex]) + + if (playbackManager.isPlayingLocally(['Video'])) { + return; } + + var newIndex = currentRotationIndex + 1; + if (newIndex >= currentRotatingImages.length) { + newIndex = 0; + } + + currentRotationIndex = newIndex; + setBackdropImage(currentRotatingImages[newIndex]); } function clearRotation() { var interval = rotationInterval; - interval && clearInterval(interval), rotationInterval = null, currentRotatingImages = [], currentRotationIndex = -1 + if (interval) { + clearInterval(interval); + } + rotationInterval = null; + currentRotatingImages = []; + currentRotationIndex = -1; } function setBackdrop(url, imageOptions) { - url && "string" != typeof url && (url = getImageUrls([url], imageOptions)[0]), url ? (clearRotation(), setBackdropImage(url)) : clearBackdrop() - } - Backdrop.prototype.load = function(url, parent, existingBackdropImage) { - var img = new Image, - self = this; - img.onload = function() { - if (!self.isDestroyed) { - var backdropImage = document.createElement("div"); - if (backdropImage.classList.add("backdropImage"), backdropImage.classList.add("displayingBackdropImage"), backdropImage.style.backgroundImage = "url('" + url + "')", backdropImage.setAttribute("data-url", url), backdropImage.classList.add("backdropImageFadeIn"), parent.appendChild(backdropImage), !enableAnimation(backdropImage)) return existingBackdropImage && existingBackdropImage.parentNode && existingBackdropImage.parentNode.removeChild(existingBackdropImage), void internalBackdrop(!0); - var onAnimationComplete = function() { - dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, { - once: !0 - }), backdropImage === self.currentAnimatingElement && (self.currentAnimatingElement = null), existingBackdropImage && existingBackdropImage.parentNode && existingBackdropImage.parentNode.removeChild(existingBackdropImage) - }; - dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, { - once: !0 - }), internalBackdrop(!0) + + if (url) { + if (typeof url !== 'string') { + url = getImageUrls([url], imageOptions)[0]; } - }, img.src = url - }, Backdrop.prototype.cancelAnimation = function() { - var elem = this.currentAnimatingElement; - elem && (elem.classList.remove("backdropImageFadeIn"), this.currentAnimatingElement = null) - }, Backdrop.prototype.destroy = function() { - this.isDestroyed = !0, this.cancelAnimation() - }; - var backdropContainer, backgroundContainer, hasInternalBackdrop, hasExternalBackdrop, currentLoadingBackdrop, rotationInterval, standardWidths = [480, 720, 1280, 1440, 1920], - currentRotatingImages = [], - currentRotationIndex = -1; + } + + if (url) { + clearRotation(); + + setBackdropImage(url); + + } else { + clearBackdrop(); + } + } + return { + setBackdrops: setBackdrops, setBackdrop: setBackdrop, clear: clearBackdrop, externalBackdrop: externalBackdrop - } + }; + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/backdrop/style.css b/src/bower_components/emby-webcomponents/backdrop/style.css index b49ac84c53..743fe72df8 100644 --- a/src/bower_components/emby-webcomponents/backdrop/style.css +++ b/src/bower_components/emby-webcomponents/backdrop/style.css @@ -1,41 +1,29 @@ .backdropContainer { - contain: layout style size + contain: layout style size; } .backdropImage { background-repeat: no-repeat; background-position: center center; - -webkit-background-size: cover; background-size: cover; position: absolute; top: 0; left: 0; right: 0; bottom: 0; - contain: layout style + contain: layout style; } .backdropImageFadeIn { - -webkit-animation: backdrop-fadein .8s ease-in normal both; - animation: backdrop-fadein .8s ease-in normal both -} - -@-webkit-keyframes backdrop-fadein { - from { - opacity: 0 - } - - to { - opacity: 1 - } + animation: backdrop-fadein 800ms ease-in normal both; } @keyframes backdrop-fadein { from { - opacity: 0 + opacity: 0; } to { - opacity: 1 + opacity: 1; } -} \ No newline at end of file +} diff --git a/src/bower_components/emby-webcomponents/browser.js b/src/bower_components/emby-webcomponents/browser.js index c718dfb6d0..cace0cb891 100644 --- a/src/bower_components/emby-webcomponents/browser.js +++ b/src/bower_components/emby-webcomponents/browser.js @@ -1,69 +1,310 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; - function supportsCssAnimation(allowPrefix) { - if (allowPrefix) { - if (!0 === _supportsCssAnimationWithPrefix || !1 === _supportsCssAnimationWithPrefix) return _supportsCssAnimationWithPrefix - } else if (!0 === _supportsCssAnimation || !1 === _supportsCssAnimation) return _supportsCssAnimation; - var animation = !1, - domPrefixes = ["Webkit", "O", "Moz"], - pfx = "", - elm = document.createElement("div"); - if (void 0 !== elm.style.animationName && (animation = !0), !1 === animation && allowPrefix) - for (var i = 0; i < domPrefixes.length; i++) - if (void 0 !== elm.style[domPrefixes[i] + "AnimationName"]) { - pfx = domPrefixes[i], pfx + "Animation", "-" + pfx.toLowerCase() + "-", animation = !0; - break - } return allowPrefix ? _supportsCssAnimationWithPrefix = animation : _supportsCssAnimation = animation + function isTv() { + + // This is going to be really difficult to get right + var userAgent = navigator.userAgent.toLowerCase(); + + if (userAgent.indexOf('tv') !== -1) { + return true; + } + + if (userAgent.indexOf('samsungbrowser') !== -1) { + return true; + } + + if (userAgent.indexOf('nintendo') !== -1) { + return true; + } + + if (userAgent.indexOf('viera') !== -1) { + return true; + } + + if (userAgent.indexOf('webos') !== -1) { + return true; + } + + return false; } - var _supportsCssAnimation, _supportsCssAnimationWithPrefix, userAgent = navigator.userAgent, - matched = function(ua) { - ua = ua.toLowerCase(); - var match = /(edge)[ \/]([\w.]+)/.exec(ua) || /(opera)[ \/]([\w.]+)/.exec(ua) || /(opr)[ \/]([\w.]+)/.exec(ua) || /(chrome)[ \/]([\w.]+)/.exec(ua) || /(safari)[ \/]([\w.]+)/.exec(ua) || /(firefox)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [], - versionMatch = /(version)[ \/]([\w.]+)/.exec(ua), - platform_match = /(ipad)/.exec(ua) || /(iphone)/.exec(ua) || /(windows)/.exec(ua) || /(android)/.exec(ua) || [], - browser = match[1] || ""; - "edge" === browser ? platform_match = [""] : -1 !== ua.indexOf("windows phone") || -1 !== ua.indexOf("iemobile") ? browser = "msie" : -1 !== ua.indexOf("like gecko") && -1 === ua.indexOf("webkit") && -1 === ua.indexOf("opera") && -1 === ua.indexOf("chrome") && -1 === ua.indexOf("safari") && (browser = "msie"), "opr" === browser && (browser = "opera"); - var version; - versionMatch && versionMatch.length > 2 && (version = versionMatch[2]), version = version || match[2] || "0"; - var versionMajor = parseInt(version.split(".")[0]); - return isNaN(versionMajor) && (versionMajor = 0), { - browser: browser, - version: version, - platform: platform_match[0] || "", - versionMajor: versionMajor + + function isMobile(userAgent) { + + var terms = [ + 'mobi', + 'ipad', + 'iphone', + 'ipod', + 'silk', + 'gt-p1000', + 'nexus 7', + 'kindle fire', + 'opera mini' + ]; + + var lower = userAgent.toLowerCase(); + + for (var i = 0, length = terms.length; i < length; i++) { + if (lower.indexOf(terms[i]) !== -1) { + return true; } - }(userAgent), - browser = {}; - return matched.browser && (browser[matched.browser] = !0, browser.version = matched.version, browser.versionMajor = matched.versionMajor), matched.platform && (browser[matched.platform] = !0), browser.chrome || browser.msie || browser.edge || browser.opera || -1 === userAgent.toLowerCase().indexOf("webkit") || (browser.safari = !0), -1 !== userAgent.toLowerCase().indexOf("playstation 4") && (browser.ps4 = !0, browser.tv = !0), - function(userAgent) { - for (var terms = ["mobi", "ipad", "iphone", "ipod", "silk", "gt-p1000", "nexus 7", "kindle fire", "opera mini"], lower = userAgent.toLowerCase(), i = 0, length = terms.length; i < length; i++) - if (-1 !== lower.indexOf(terms[i])) return !0; - return !1 - }(userAgent) && (browser.mobile = !0), browser.xboxOne = -1 !== userAgent.toLowerCase().indexOf("xbox"), browser.animate = "undefined" != typeof document && null != document.documentElement.animate, browser.tizen = -1 !== userAgent.toLowerCase().indexOf("tizen") || null != self.tizen, browser.web0s = -1 !== userAgent.toLowerCase().indexOf("Web0S".toLowerCase()), browser.edgeUwp = browser.edge && (-1 !== userAgent.toLowerCase().indexOf("msapphost") || -1 !== userAgent.toLowerCase().indexOf("webview")), browser.tizen || (browser.orsay = -1 !== userAgent.toLowerCase().indexOf("smarthub")), browser.edgeUwp && (browser.edge = !0), browser.tv = function() { - var userAgent = navigator.userAgent.toLowerCase(); - return -1 !== userAgent.indexOf("tv") || (-1 !== userAgent.indexOf("samsungbrowser") || (-1 !== userAgent.indexOf("nintendo") || (-1 !== userAgent.indexOf("viera") || -1 !== userAgent.indexOf("webos")))) - }(), browser.operaTv = browser.tv && -1 !== userAgent.toLowerCase().indexOf("opr/"), - function(prop, value) { - if ("undefined" == typeof window) return !1; - if (value = 2 === arguments.length ? value : "inherit", "CSS" in window && "supports" in window.CSS) return window.CSS.supports(prop, value); - if ("supportsCSS" in window) return window.supportsCSS(prop, value); - try { - var camel = prop.replace(/-([a-z]|[0-9])/gi, function(all, letter) { - return (letter + "").toUpperCase() - }), - support = camel in el.style, - el = document.createElement("div"); - return el.style.cssText = prop + ":" + value, support && "" !== el.style[camel] - } catch (err) { - return !1 + } + + return false; + } + + 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 + if ('CSS' in window && 'supports' in window.CSS) { + return window.CSS.supports(prop, value); + } + // Check Opera's native method + if ('supportsCSS' in window) { + return window.supportsCSS(prop, value); + } + + // need try/catch because it's failing on tizen + + try { + // Convert to camel-case for DOM interactions + var camel = prop.replace(/-([a-z]|[0-9])/ig, function (all, letter) { + return (letter + '').toUpperCase(); + }); + // Check if the property is supported + var support = (camel in el.style); + // Create test element + var el = document.createElement('div'); + // Assign the property and value to invoke + // the CSS interpreter + el.style.cssText = prop + ':' + value; + // Ensure both the property and value are + // supported and return + return support && (el.style[camel] !== ''); + } catch (err) { + return false; + } + } + + function hasKeyboard(browser) { + + if (browser.touch) { + return true; + } + + if (browser.xboxOne) { + return true; + } + + if (browser.ps4) { + return true; + } + + if (browser.edgeUwp) { + // This is OK for now, but this won't always be true + // Should we use this? + // https://gist.github.com/wagonli/40d8a31bd0d6f0dd7a5d + return true; + } + + if (browser.tv) { + return true; + } + + return false; + } + + function iOSversion() { + if (/iP(hone|od|ad)/.test(navigator.platform)) { + // supports iOS 2.0 and later: + var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/); + return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)]; + } + } + + var _supportsCssAnimation; + var _supportsCssAnimationWithPrefix; + function supportsCssAnimation(allowPrefix) { + + if (allowPrefix) { + if (_supportsCssAnimationWithPrefix === true || _supportsCssAnimationWithPrefix === false) { + return _supportsCssAnimationWithPrefix; } - }("display", "flex") || (browser.noFlex = !0), (browser.mobile || browser.tv) && (browser.slow = !0), "undefined" != typeof document && ("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch) && (browser.touch = !0), browser.keyboard = function(browser) { - return !!browser.touch || (!!browser.xboxOne || (!!browser.ps4 || (!!browser.edgeUwp || !!browser.tv))) - }(browser), browser.supportsCssAnimation = supportsCssAnimation, browser.osx = -1 !== userAgent.toLowerCase().indexOf("os x"), browser.iOS = browser.ipad || browser.iphone || browser.ipod, browser.iOS && (browser.iOSVersion = function() { - if (/iP(hone|od|ad)/.test(navigator.platform)) { - var v = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/); - return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)] + } else { + if (_supportsCssAnimation === true || _supportsCssAnimation === false) { + return _supportsCssAnimation; } - }(), browser.iOSVersion = browser.iOSVersion[0] + browser.iOSVersion[1] / 10), browser.chromecast = browser.chrome && -1 !== userAgent.toLowerCase().indexOf("crkey"), browser + } + + 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(); + + var match = /(edge)[ \/]([\w.]+)/.exec(ua) || + /(opera)[ \/]([\w.]+)/.exec(ua) || + /(opr)[ \/]([\w.]+)/.exec(ua) || + /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(safari)[ \/]([\w.]+)/.exec(ua) || + /(firefox)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + var versionMatch = /(version)[ \/]([\w.]+)/.exec(ua); + + var platform_match = /(ipad)/.exec(ua) || + /(iphone)/.exec(ua) || + /(windows)/.exec(ua) || + /(android)/.exec(ua) || + []; + + var browser = match[1] || ""; + + if (browser === "edge") { + platform_match = [""]; + } else { + if (ua.indexOf("windows phone") !== -1 || ua.indexOf("iemobile") !== -1) { + + // http://www.neowin.net/news/ie11-fakes-user-agent-to-fool-gmail-in-windows-phone-81-gdr1-update + browser = "msie"; + } + else if (ua.indexOf("like gecko") !== -1 && ua.indexOf('webkit') === -1 && ua.indexOf('opera') === -1 && ua.indexOf('chrome') === -1 && ua.indexOf('safari') === -1) { + browser = "msie"; + } + } + + if (browser === 'opr') { + browser = 'opera'; + } + + var version; + if (versionMatch && versionMatch.length > 2) { + version = versionMatch[2]; + } + + version = version || match[2] || "0"; + + var versionMajor = parseInt(version.split('.')[0]); + + if (isNaN(versionMajor)) { + versionMajor = 0; + } + + return { + browser: browser, + version: version, + platform: platform_match[0] || "", + versionMajor: versionMajor + }; + }; + + var userAgent = navigator.userAgent; + + var matched = uaMatch(userAgent); + var browser = {}; + + if (matched.browser) { + browser[matched.browser] = true; + browser.version = matched.version; + browser.versionMajor = matched.versionMajor; + } + + if (matched.platform) { + browser[matched.platform] = true; + } + + if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf("webkit") !== -1) { + browser.safari = true; + } + + if (userAgent.toLowerCase().indexOf("playstation 4") !== -1) { + browser.ps4 = true; + browser.tv = true; + } + + if (isMobile(userAgent)) { + browser.mobile = true; + } + + browser.xboxOne = userAgent.toLowerCase().indexOf('xbox') !== -1; + browser.animate = typeof document !== 'undefined' && document.documentElement.animate != null; + browser.tizen = userAgent.toLowerCase().indexOf('tizen') !== -1 || self.tizen != null; + browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1; + browser.edgeUwp = browser.edge && (userAgent.toLowerCase().indexOf('msapphost') !== -1 || userAgent.toLowerCase().indexOf('webview') !== -1); + + if (!browser.tizen) { + browser.orsay = userAgent.toLowerCase().indexOf('smarthub') !== -1; + } + + if (browser.edgeUwp) { + browser.edge = true; + } + + browser.tv = isTv(); + browser.operaTv = browser.tv && userAgent.toLowerCase().indexOf('opr/') !== -1; + + if (!isStyleSupported('display', 'flex')) { + browser.noFlex = true; + } + + if (browser.mobile || browser.tv) { + browser.slow = 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; + + if (browser.iOS) { + browser.iOSVersion = iOSversion(); + browser.iOSVersion = browser.iOSVersion[0] + (browser.iOSVersion[1] / 10); + } + + browser.chromecast = browser.chrome && userAgent.toLowerCase().indexOf('crkey') !== -1; + + return browser; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/browserdeviceprofile.js b/src/bower_components/emby-webcomponents/browserdeviceprofile.js index f4178a750a..7b37a0cdb1 100644 --- a/src/bower_components/emby-webcomponents/browserdeviceprofile.js +++ b/src/bower_components/emby-webcomponents/browserdeviceprofile.js @@ -1,384 +1,916 @@ -define(["browser"], function(browser) { - "use strict"; +define(['browser'], function (browser) { + 'use strict'; function canPlayH264(videoTestElement) { - return !(!videoTestElement.canPlayType || !videoTestElement.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, "")) + return !!(videoTestElement.canPlayType && videoTestElement.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, '')); } function canPlayH265(videoTestElement, options) { - if (browser.tizen || browser.orsay || browser.xboxOne || browser.web0s || options.supportsHevc) return !0; - var userAgent = navigator.userAgent.toLowerCase(); - if (browser.chromecast) { - if (-1 !== userAgent.indexOf("aarch64")) return !0 + + if (browser.tizen || browser.orsay || browser.xboxOne || browser.web0s || options.supportsHevc) { + return true; } - return !!(browser.iOS && (browser.iOSVersion || 0) >= 11) || !(!videoTestElement.canPlayType || !videoTestElement.canPlayType('video/hevc; codecs="hevc, aac"').replace(/no/, "")) + + var userAgent = navigator.userAgent.toLowerCase(); + + if (browser.chromecast) { + + var isChromecastUltra = userAgent.indexOf('aarch64') !== -1; + if (isChromecastUltra) { + return true; + } + } + + // Unfortunately haven't yet found a canPlayType for proper detection + if (browser.iOS && (browser.iOSVersion || 0) >= 11) { + return true; + } + + return !!(videoTestElement.canPlayType && videoTestElement.canPlayType('video/hevc; codecs="hevc, aac"').replace(/no/, '')); } + var _supportsTextTracks; function supportsTextTracks() { - return !(!browser.tizen && !browser.orsay) || (null == _supportsTextTracks && (_supportsTextTracks = null != document.createElement("video").textTracks), _supportsTextTracks) + + if (browser.tizen || browser.orsay) { + return true; + } + + if (_supportsTextTracks == null) { + _supportsTextTracks = document.createElement('video').textTracks != null; + } + + // For now, until ready + return _supportsTextTracks; } + var _canPlayHls; function canPlayHls(src) { - return null == _canPlayHls && (_canPlayHls = canPlayNativeHls() || canPlayHlsWithMSE()), _canPlayHls + + if (_canPlayHls == null) { + _canPlayHls = canPlayNativeHls() || canPlayHlsWithMSE(); + } + return _canPlayHls; } function canPlayNativeHls() { - if (browser.tizen || browser.orsay) return !0; - var media = document.createElement("video"); - return !(!media.canPlayType("application/x-mpegURL").replace(/no/, "") && !media.canPlayType("application/vnd.apple.mpegURL").replace(/no/, "")) + + if (browser.tizen || browser.orsay) { + return true; + } + + var media = document.createElement('video'); + if (media.canPlayType('application/x-mpegURL').replace(/no/, '') || + media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) { + return true; + } + + return false; } function canPlayHlsWithMSE() { - return null != window.MediaSource + if (window.MediaSource != null) { + // text tracks don’t work with this in firefox + return true; + } + + return false; } function canPlayAudioFormat(format) { + var typeString; - if ("flac" === format) { - if (browser.tizen || browser.orsay || browser.web0s) return !0; - if (browser.edgeUwp) return !0 - } else if ("wma" === format) { - if (browser.tizen || browser.orsay) return !0; - if (browser.edgeUwp) return !0 - } else { - if ("opus" === format) return typeString = 'audio/ogg; codecs="opus"', !!document.createElement("audio").canPlayType(typeString).replace(/no/, ""); - if ("mp2" === format) return !1 + + if (format === 'flac') { + if (browser.tizen || browser.orsay || browser.web0s) { + return true; + } + if (browser.edgeUwp) { + return true; + } } - if ("webma" === format) typeString = "audio/webm"; - else if ("mp2" === format) typeString = "audio/mpeg"; - else if ("ogg" === format || "oga" === format) { - if (browser.chrome) return !1; - typeString = "audio/" + format - } else typeString = "audio/" + format; - return !!document.createElement("audio").canPlayType(typeString).replace(/no/, "") + + else if (format === 'wma') { + if (browser.tizen || browser.orsay) { + return true; + } + if (browser.edgeUwp) { + return true; + } + } + + else if (format === 'opus') { + typeString = 'audio/ogg; codecs="opus"'; + + if (document.createElement('audio').canPlayType(typeString).replace(/no/, '')) { + return true; + } + + return false; + } + + else if (format === 'mp2') { + + // For now + return false; + } + + if (format === 'webma') { + typeString = 'audio/webm'; + } else if (format === 'mp2') { + typeString = 'audio/mpeg'; + } else if (format === 'ogg' || format === 'oga') { + + // chrome says probably, but seeing failures + if (browser.chrome) { + return false; + } + typeString = 'audio/' + format; + + } else { + typeString = 'audio/' + format; + } + + if (document.createElement('audio').canPlayType(typeString).replace(/no/, '')) { + return true; + } + + return false; } function testCanPlayMkv(videoTestElement) { - if (browser.tizen || browser.orsay || browser.web0s) return !0; - if (videoTestElement.canPlayType("video/x-matroska").replace(/no/, "") || videoTestElement.canPlayType("video/mkv").replace(/no/, "")) return !0; + + if (browser.tizen || browser.orsay || browser.web0s) { + return true; + } + + if (videoTestElement.canPlayType('video/x-matroska').replace(/no/, '') || + videoTestElement.canPlayType('video/mkv').replace(/no/, '')) { + return true; + } + var userAgent = navigator.userAgent.toLowerCase(); - return browser.chrome ? !browser.operaTv && (-1 === userAgent.indexOf("vivaldi") && -1 === userAgent.indexOf("opera")) : !!browser.edgeUwp + + // Unfortunately there's no real way to detect mkv support + if (browser.chrome) { + + // Not supported on opera tv + if (browser.operaTv) { + return false; + } + + // Filter out browsers based on chromium that don't support mkv + if (userAgent.indexOf('vivaldi') !== -1 || userAgent.indexOf('opera') !== -1) { + return false; + } + + return true; + } + + if (browser.edgeUwp) { + + return true; + } + + return false; } function testCanPlayTs() { - return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp + return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; } function supportsMpeg2Video() { - return browser.orsay || browser.tizen || browser.edgeUwp || browser.web0s + return browser.orsay || browser.tizen || browser.edgeUwp || browser.web0s; } function supportsVc1() { - return browser.orsay || browser.tizen || browser.edgeUwp || browser.web0s + return browser.orsay || browser.tizen || browser.edgeUwp || browser.web0s; + } + + function getFlvMseDirectPlayProfile() { + + var videoAudioCodecs = ['aac']; + + if (!browser.edge && !browser.msie) { + videoAudioCodecs.push('mp3'); + } + + return { + Container: 'flv', + Type: 'Video', + VideoCodec: 'h264', + AudioCodec: videoAudioCodecs.join(',') + }; } function getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) { - var supported = !1, - profileContainer = container, - videoCodecs = []; + + var supported = false; + var profileContainer = container; + var videoCodecs = []; + switch (container) { - case "asf": - supported = browser.tizen || browser.orsay || browser.edgeUwp, videoAudioCodecs = []; + + case 'asf': + supported = browser.tizen || browser.orsay || browser.edgeUwp; + videoAudioCodecs = []; break; - case "avi": + case 'avi': supported = browser.tizen || browser.orsay || browser.edgeUwp; break; - case "mpg": - case "mpeg": + case 'mpg': + case 'mpeg': supported = browser.edgeUwp || browser.tizen || browser.orsay; break; - case "flv": + case 'flv': + supported = browser.tizen || browser.orsay; + //if (!supported && window.MediaSource != null && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"')) { + // return getFlvMseDirectPlayProfile(); + //} + break; + case '3gp': + case 'mts': + case 'trp': + case 'vob': + case 'vro': supported = browser.tizen || browser.orsay; break; - case "3gp": - case "mts": - case "trp": - case "vob": - case "vro": - supported = browser.tizen || browser.orsay; + case 'mov': + supported = browser.tizen || browser.orsay || browser.chrome || browser.edgeUwp; + videoCodecs.push('h264'); break; - case "mov": - supported = browser.tizen || browser.orsay || browser.chrome || browser.edgeUwp, videoCodecs.push("h264"); + case 'm2ts': + supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; + videoCodecs.push('h264'); + if (supportsVc1()) { + videoCodecs.push('vc1'); + } + if (supportsMpeg2Video()) { + videoCodecs.push('mpeg2video'); + } break; - case "m2ts": - supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp, videoCodecs.push("h264"), supportsVc1() && videoCodecs.push("vc1"), supportsMpeg2Video() && videoCodecs.push("mpeg2video"); + case 'wmv': + supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; + videoAudioCodecs = []; break; - case "wmv": - supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp, videoAudioCodecs = []; + case 'ts': + supported = testCanPlayTs(); + videoCodecs.push('h264'); + if (canPlayH265(videoTestElement, options)) { + videoCodecs.push('h265'); + videoCodecs.push('hevc'); + } + if (supportsVc1()) { + videoCodecs.push('vc1'); + } + if (supportsMpeg2Video()) { + videoCodecs.push('mpeg2video'); + } + profileContainer = 'ts,mpegts'; + break; + default: break; - case "ts": - supported = testCanPlayTs(), videoCodecs.push("h264"), canPlayH265(videoTestElement, options) && (videoCodecs.push("h265"), videoCodecs.push("hevc")), supportsVc1() && videoCodecs.push("vc1"), supportsMpeg2Video() && videoCodecs.push("mpeg2video"), profileContainer = "ts,mpegts" } - return supported ? { + + if (!supported) { + return null; + } + + return { Container: profileContainer, - Type: "Video", - VideoCodec: videoCodecs.join(","), - AudioCodec: videoAudioCodecs.join(",") - } : null + Type: 'Video', + VideoCodec: videoCodecs.join(','), + AudioCodec: videoAudioCodecs.join(',') + }; + } + + function getMaxBitrate() { + + return 120000000; } function getGlobalMaxVideoBitrate() { + var userAgent = navigator.userAgent.toLowerCase(); + if (browser.chromecast) { - return -1 !== userAgent.indexOf("aarch64") ? null : self.screen && self.screen.width >= 3800 ? null : 3e7 + + var isChromecastUltra = userAgent.indexOf('aarch64') !== -1; + if (isChromecastUltra) { + return null; + } + + // This is a hack to try and detect chromecast on vizio + if (self.screen && self.screen.width >= 3800) { + return null; + } + + return 30000000; } - var isTizenFhd = !1; - if (browser.tizen) try { - isTizenFhd = !webapis.productinfo.isUdPanelSupported(), console.log("isTizenFhd = " + isTizenFhd) - } catch (error) { - console.log("isUdPanelSupported() error code = " + error.code) + + var isTizenFhd = false; + if (browser.tizen) { + try { + var isTizenUhd = webapis.productinfo.isUdPanelSupported(); + isTizenFhd = !isTizenUhd; + console.log("isTizenFhd = " + isTizenFhd); + } catch (error) { + console.log("isUdPanelSupported() error code = " + error.code); + } } - return browser.ps4 ? 8e6 : browser.xboxOne ? 12e6 : browser.edgeUwp ? null : browser.tizen && isTizenFhd ? 2e7 : null + + return browser.ps4 ? 8000000 : + (browser.xboxOne ? 12000000 : + (browser.edgeUwp ? null : + (browser.tizen && isTizenFhd ? 20000000 : null))); } function supportsAc3(videoTestElement) { - return !!(browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s) || videoTestElement.canPlayType('audio/mp4; codecs="ac-3"').replace(/no/, "") && !browser.osx && !browser.iOS + + if (browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s) { + return true; + } + + return (videoTestElement.canPlayType('audio/mp4; codecs="ac-3"').replace(/no/, '') && !browser.osx && !browser.iOS); } function supportsEac3(videoTestElement) { - return !!(browser.tizen || browser.orsay || browser.web0s) || videoTestElement.canPlayType('audio/mp4; codecs="ec-3"').replace(/no/, "") + + if (browser.tizen || browser.orsay || browser.web0s) { + return true; + } + + return videoTestElement.canPlayType('audio/mp4; codecs="ec-3"').replace(/no/, ''); } - var _supportsTextTracks, _canPlayHls; - return function(options) { + + return function (options) { + options = options || {}; - var physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2), - videoTestElement = document.createElement("video"), - canPlayVp8 = videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/, ""), - canPlayVp9 = videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/, ""), - webmAudioCodecs = ["vorbis"], - canPlayMkv = testCanPlayMkv(videoTestElement), - profile = {}; - profile.MaxStreamingBitrate = 12e7, profile.MaxStaticBitrate = 1e8, profile.MusicStreamingTranscodingBitrate = Math.min(12e7, 192e3), profile.DirectPlayProfiles = []; - var videoAudioCodecs = [], - hlsVideoAudioCodecs = [], - supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, "") || videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, ""), - supportsMp2VideoAudio = browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s, - maxVideoWidth = browser.xboxOne && self.screen ? self.screen.width : null; - options.maxVideoWidth && (maxVideoWidth = options.maxVideoWidth); - var canPlayAacVideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/, ""); - if (canPlayAacVideoAudio && browser.chromecast && physicalAudioChannels <= 2 && videoAudioCodecs.push("aac"), supportsAc3(videoTestElement)) { - videoAudioCodecs.push("ac3"); + var physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2); + + var bitrateSetting = getMaxBitrate(); + + var videoTestElement = document.createElement('video'); + + var canPlayVp8 = videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/, ''); + var canPlayVp9 = videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/, ''); + var webmAudioCodecs = ['vorbis']; + + var canPlayMkv = testCanPlayMkv(videoTestElement); + + var profile = {}; + + profile.MaxStreamingBitrate = bitrateSetting; + profile.MaxStaticBitrate = 100000000; + profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 192000); + + profile.DirectPlayProfiles = []; + + var videoAudioCodecs = []; + var hlsVideoAudioCodecs = []; + + var supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '') || + videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, ''); + + // Not sure how to test for this + var supportsMp2VideoAudio = browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s; + + var maxVideoWidth = browser.xboxOne ? + (self.screen ? self.screen.width : null) : + null; + + if (options.maxVideoWidth) { + maxVideoWidth = options.maxVideoWidth; + } + + var canPlayAacVideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/, ''); + + if (canPlayAacVideoAudio && browser.chromecast && physicalAudioChannels <= 2) { + // prioritize this first + videoAudioCodecs.push('aac'); + } + + // Only put mp3 first if mkv support is there + // Otherwise with HLS and mp3 audio we're seeing some browsers + // safari is lying + if (supportsAc3(videoTestElement)) { + + videoAudioCodecs.push('ac3'); + var eAc3 = supportsEac3(videoTestElement); - eAc3 && videoAudioCodecs.push("eac3"); - (!browser.edge || !browser.touch || browser.edgeUwp) && (hlsVideoAudioCodecs.push("ac3"), eAc3 && hlsVideoAudioCodecs.push("eac3")) + if (eAc3) { + videoAudioCodecs.push('eac3'); + } + + // This works in edge desktop, but not mobile + // TODO: Retest this on mobile + var supportsAc3InHls = (!browser.edge || !browser.touch || browser.edgeUwp); + if (supportsAc3InHls) { + hlsVideoAudioCodecs.push('ac3'); + if (eAc3) { + hlsVideoAudioCodecs.push('eac3'); + } + } } - canPlayAacVideoAudio && browser.chromecast && -1 === videoAudioCodecs.indexOf("aac") && videoAudioCodecs.push("aac"), supportsMp3VideoAudio && (videoAudioCodecs.push("mp3"), browser.ps4 || physicalAudioChannels <= 2 && hlsVideoAudioCodecs.push("mp3")), canPlayAacVideoAudio && (-1 === videoAudioCodecs.indexOf("aac") && videoAudioCodecs.push("aac"), hlsVideoAudioCodecs.push("aac")), supportsMp3VideoAudio && (browser.ps4 || -1 === hlsVideoAudioCodecs.indexOf("mp3") && hlsVideoAudioCodecs.push("mp3")), supportsMp2VideoAudio && videoAudioCodecs.push("mp2"); + + if (canPlayAacVideoAudio && browser.chromecast && videoAudioCodecs.indexOf('aac') === -1) { + // prioritize this first + videoAudioCodecs.push('aac'); + } + + if (supportsMp3VideoAudio) { + videoAudioCodecs.push('mp3'); + + // PS4 fails to load HLS with mp3 audio + if (!browser.ps4) { + + // mp3 encoder only supports 2 channels, so only make that preferred if we're only requesting 2 channels + // Also apply it for chromecast because it no longer supports AAC 5.1 + if (physicalAudioChannels <= 2) { + hlsVideoAudioCodecs.push('mp3'); + } + } + } + if (canPlayAacVideoAudio) { + + if (videoAudioCodecs.indexOf('aac') === -1) { + videoAudioCodecs.push('aac'); + } + + hlsVideoAudioCodecs.push('aac'); + } + if (supportsMp3VideoAudio) { + // PS4 fails to load HLS with mp3 audio + if (!browser.ps4) { + if (hlsVideoAudioCodecs.indexOf('mp3') === -1) { + hlsVideoAudioCodecs.push('mp3'); + } + } + } + + if (supportsMp2VideoAudio) { + videoAudioCodecs.push('mp2'); + } + 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"); - v && parseFloat(v) >= parseFloat("4.0") && (supportsDts = !1) + 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')) { + supportsDts = false; + } } - supportsDts && (videoAudioCodecs.push("dca"), videoAudioCodecs.push("dts")), (browser.tizen || browser.orsay || browser.web0s) && (videoAudioCodecs.push("pcm_s16le"), videoAudioCodecs.push("pcm_s24le")), options.supportsTrueHd && videoAudioCodecs.push("truehd"), (browser.tizen || browser.orsay) && videoAudioCodecs.push("aac_latm"), canPlayAudioFormat("opus") && (videoAudioCodecs.push("opus"), hlsVideoAudioCodecs.push("opus"), webmAudioCodecs.push("opus")), canPlayAudioFormat("flac") && videoAudioCodecs.push("flac"), videoAudioCodecs = videoAudioCodecs.filter(function(c) { - return -1 === (options.disableVideoAudioCodecs || []).indexOf(c) - }), hlsVideoAudioCodecs = hlsVideoAudioCodecs.filter(function(c) { - return -1 === (options.disableHlsVideoAudioCodecs || []).indexOf(c) + + if (supportsDts) { + videoAudioCodecs.push('dca'); + videoAudioCodecs.push('dts'); + } + + if (browser.tizen || browser.orsay || browser.web0s) { + videoAudioCodecs.push('pcm_s16le'); + videoAudioCodecs.push('pcm_s24le'); + } + + if (options.supportsTrueHd) { + videoAudioCodecs.push('truehd'); + } + + if (browser.tizen || browser.orsay) { + videoAudioCodecs.push('aac_latm'); + } + + if (canPlayAudioFormat('opus')) { + videoAudioCodecs.push('opus'); + hlsVideoAudioCodecs.push('opus'); + webmAudioCodecs.push('opus'); + } + + if (canPlayAudioFormat('flac')) { + videoAudioCodecs.push('flac'); + } + + videoAudioCodecs = videoAudioCodecs.filter(function (c) { + return (options.disableVideoAudioCodecs || []).indexOf(c) === -1; }); - var mp4VideoCodecs = [], - hlsVideoCodecs = []; - canPlayH264(videoTestElement) && (mp4VideoCodecs.push("h264"), hlsVideoCodecs.push("h264")), canPlayH265(videoTestElement, options) && (mp4VideoCodecs.push("h265"), mp4VideoCodecs.push("hevc"), (browser.tizen || browser.web0s) && (hlsVideoCodecs.push("h265"), hlsVideoCodecs.push("hevc"))), supportsMpeg2Video() && mp4VideoCodecs.push("mpeg2video"), supportsVc1() && mp4VideoCodecs.push("vc1"), (browser.tizen || browser.orsay) && mp4VideoCodecs.push("msmpeg4v2"), canPlayVp8 && mp4VideoCodecs.push("vp8"), canPlayVp9 && mp4VideoCodecs.push("vp9"), (canPlayVp8 || browser.tizen || browser.orsay) && videoAudioCodecs.push("vorbis"), mp4VideoCodecs.length && profile.DirectPlayProfiles.push({ - Container: "mp4,m4v", - Type: "Video", - VideoCodec: mp4VideoCodecs.join(","), - AudioCodec: videoAudioCodecs.join(",") - }), canPlayMkv && mp4VideoCodecs.length && profile.DirectPlayProfiles.push({ - Container: "mkv", - Type: "Video", - VideoCodec: mp4VideoCodecs.join(","), - AudioCodec: videoAudioCodecs.join(",") - }), ["m2ts", "wmv", "ts", "asf", "avi", "mpg", "mpeg", "flv", "3gp", "mts", "trp", "vob", "vro", "mov"].map(function(container) { - return getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) - }).filter(function(i) { - return null != i - }).forEach(function(i) { - profile.DirectPlayProfiles.push(i) - }), ["opus", "mp3", "mp2", "aac", "flac", "alac", "webma", "wma", "wav", "ogg", "oga"].filter(canPlayAudioFormat).forEach(function(audioFormat) { - "mp2" === audioFormat ? profile.DirectPlayProfiles.push({ - Container: "mp2,mp3", - Type: "Audio", - AudioCodec: audioFormat - }) : "mp3" === audioFormat ? profile.DirectPlayProfiles.push({ - Container: audioFormat, - Type: "Audio", - AudioCodec: audioFormat - }) : profile.DirectPlayProfiles.push({ - Container: "webma" === audioFormat ? "webma,webm" : audioFormat, - Type: "Audio" - }), "aac" !== audioFormat && "alac" !== audioFormat || profile.DirectPlayProfiles.push({ - Container: "m4a", - AudioCodec: audioFormat, - Type: "Audio" - }) - }), canPlayVp8 && profile.DirectPlayProfiles.push({ - Container: "webm", - Type: "Video", - AudioCodec: webmAudioCodecs.join(","), - VideoCodec: "VP8" - }), canPlayVp9 && profile.DirectPlayProfiles.push({ - Container: "webm", - Type: "Video", - AudioCodec: webmAudioCodecs.join(","), - VideoCodec: "VP9" - }), profile.TranscodingProfiles = []; - var hlsBreakOnNonKeyFrames = !(!(browser.iOS || browser.osx || browser.edge) && canPlayNativeHls()); - canPlayHls() && !1 !== browser.enableHlsAudio && profile.TranscodingProfiles.push({ - Container: !canPlayNativeHls() || browser.edge || browser.android ? "ts" : "aac", - Type: "Audio", - AudioCodec: "aac", - Context: "Streaming", - Protocol: "hls", - MaxAudioChannels: physicalAudioChannels.toString(), - MinSegments: browser.iOS || browser.osx ? "2" : "1", - BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames - }), ["aac", "mp3", "opus", "wav"].filter(canPlayAudioFormat).forEach(function(audioFormat) { + + hlsVideoAudioCodecs = hlsVideoAudioCodecs.filter(function (c) { + return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1; + }); + + var mp4VideoCodecs = []; + var hlsVideoCodecs = []; + + if (canPlayH264(videoTestElement)) { + mp4VideoCodecs.push('h264'); + hlsVideoCodecs.push('h264'); + } + if (canPlayH265(videoTestElement, options)) { + mp4VideoCodecs.push('h265'); + mp4VideoCodecs.push('hevc'); + + if (browser.tizen || browser.web0s) { + hlsVideoCodecs.push('h265'); + hlsVideoCodecs.push('hevc'); + } + } + + if (supportsMpeg2Video()) { + mp4VideoCodecs.push('mpeg2video'); + } + + if (supportsVc1()) { + mp4VideoCodecs.push('vc1'); + } + + if (browser.tizen || browser.orsay) { + mp4VideoCodecs.push('msmpeg4v2'); + } + + if (canPlayVp8) { + mp4VideoCodecs.push('vp8'); + } + if (canPlayVp9) { + mp4VideoCodecs.push('vp9'); + } + + if (canPlayVp8 || browser.tizen || browser.orsay) { + videoAudioCodecs.push('vorbis'); + } + + if (mp4VideoCodecs.length) { + profile.DirectPlayProfiles.push({ + Container: 'mp4,m4v', + Type: 'Video', + VideoCodec: mp4VideoCodecs.join(','), + AudioCodec: videoAudioCodecs.join(',') + }); + } + + if (canPlayMkv && mp4VideoCodecs.length) { + profile.DirectPlayProfiles.push({ + Container: 'mkv', + Type: 'Video', + VideoCodec: mp4VideoCodecs.join(','), + AudioCodec: videoAudioCodecs.join(',') + }); + } + + // These are formats we can't test for but some devices will support + ['m2ts', 'wmv', 'ts', 'asf', 'avi', 'mpg', 'mpeg', 'flv', '3gp', 'mts', 'trp', 'vob', 'vro', 'mov'].map(function (container) { + return getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options); + }).filter(function (i) { + return i != null; + }).forEach(function (i) { + profile.DirectPlayProfiles.push(i); + }); + + ['opus', 'mp3', 'mp2', 'aac', 'flac', 'alac', 'webma', 'wma', 'wav', 'ogg', 'oga'].filter(canPlayAudioFormat).forEach(function (audioFormat) { + + if (audioFormat === 'mp2') { + + profile.DirectPlayProfiles.push({ + Container: 'mp2,mp3', + Type: 'Audio', + AudioCodec: audioFormat + }); + } + + else if (audioFormat === 'mp3') { + + profile.DirectPlayProfiles.push({ + Container: audioFormat, + Type: 'Audio', + AudioCodec: audioFormat + }); + + } else { + profile.DirectPlayProfiles.push({ + Container: audioFormat === 'webma' ? 'webma,webm' : audioFormat, + Type: 'Audio' + }); + } + + // aac also appears in the m4a container + if (audioFormat === 'aac' || audioFormat === 'alac') { + + profile.DirectPlayProfiles.push({ + Container: 'm4a', + AudioCodec: audioFormat, + Type: 'Audio' + }); + } + }); + + if (canPlayVp8) { + profile.DirectPlayProfiles.push({ + Container: 'webm', + Type: 'Video', + AudioCodec: webmAudioCodecs.join(','), + VideoCodec: 'VP8' + }); + } + + if (canPlayVp9) { + profile.DirectPlayProfiles.push({ + Container: 'webm', + Type: 'Video', + AudioCodec: webmAudioCodecs.join(','), + VideoCodec: 'VP9' + }); + } + + profile.TranscodingProfiles = []; + + var hlsBreakOnNonKeyFrames = browser.iOS || browser.osx || browser.edge || !canPlayNativeHls() ? true : false; + + if (canPlayHls() && browser.enableHlsAudio !== false) { + profile.TranscodingProfiles.push({ + + // hlsjs, edge, and android all seem to require ts container + Container: !canPlayNativeHls() || browser.edge || browser.android ? 'ts' : 'aac', + Type: 'Audio', + AudioCodec: 'aac', + Context: 'Streaming', + Protocol: 'hls', + MaxAudioChannels: physicalAudioChannels.toString(), + MinSegments: browser.iOS || browser.osx ? '2' : '1', + BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames + }); + } + + // For streaming, prioritize opus transcoding after mp3/aac. It is too problematic with random failures + // But for static (offline sync), it will be just fine. + // Prioritize aac higher because the encoder can accept more channels than mp3 + ['aac', 'mp3', 'opus', 'wav'].filter(canPlayAudioFormat).forEach(function (audioFormat) { + profile.TranscodingProfiles.push({ Container: audioFormat, - Type: "Audio", + Type: 'Audio', AudioCodec: audioFormat, - Context: "Streaming", - Protocol: "http", + Context: 'Streaming', + Protocol: 'http', MaxAudioChannels: physicalAudioChannels.toString() - }) - }), ["opus", "mp3", "aac", "wav"].filter(canPlayAudioFormat).forEach(function(audioFormat) { + }); + }); + + ['opus', 'mp3', 'aac', 'wav'].filter(canPlayAudioFormat).forEach(function (audioFormat) { + profile.TranscodingProfiles.push({ Container: audioFormat, - Type: "Audio", + Type: 'Audio', AudioCodec: audioFormat, - Context: "Static", - Protocol: "http", + Context: 'Static', + Protocol: 'http', MaxAudioChannels: physicalAudioChannels.toString() - }) - }), !canPlayMkv || browser.tizen || browser.orsay || !1 === options.enableMkvProgressive || profile.TranscodingProfiles.push({ - Container: "mkv", - Type: "Video", - AudioCodec: videoAudioCodecs.join(","), - VideoCodec: mp4VideoCodecs.join(","), - Context: "Streaming", - MaxAudioChannels: physicalAudioChannels.toString(), - CopyTimestamps: !0 - }), canPlayMkv && profile.TranscodingProfiles.push({ - Container: "mkv", - Type: "Video", - AudioCodec: videoAudioCodecs.join(","), - VideoCodec: mp4VideoCodecs.join(","), - Context: "Static", - MaxAudioChannels: physicalAudioChannels.toString(), - CopyTimestamps: !0 - }), canPlayHls() && !1 !== options.enableHls && profile.TranscodingProfiles.push({ - Container: "ts", - Type: "Video", - AudioCodec: hlsVideoAudioCodecs.join(","), - VideoCodec: hlsVideoCodecs.join(","), - Context: "Streaming", - Protocol: "hls", - MaxAudioChannels: physicalAudioChannels.toString(), - MinSegments: browser.iOS || browser.osx ? "2" : "1", - BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames - }), canPlayVp8 && profile.TranscodingProfiles.push({ - Container: "webm", - Type: "Video", - AudioCodec: "vorbis", - VideoCodec: "vpx", - Context: "Streaming", - Protocol: "http", - MaxAudioChannels: physicalAudioChannels.toString() - }), profile.TranscodingProfiles.push({ - Container: "mp4", - Type: "Video", - AudioCodec: videoAudioCodecs.join(","), - VideoCodec: "h264", - Context: "Static", - Protocol: "http" - }), profile.ContainerProfiles = [], profile.CodecProfiles = []; - var supportsSecondaryAudio = browser.tizen || browser.orsay || videoTestElement.audioTracks, - aacCodecProfileConditions = []; - videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.5"').replace(/no/, "") || aacCodecProfileConditions.push({ - Condition: "NotEquals", - Property: "AudioProfile", - Value: "HE-AAC" - }), supportsSecondaryAudio || aacCodecProfileConditions.push({ - Condition: "Equals", - Property: "IsSecondaryAudio", - Value: "false", - IsRequired: "false" - }), browser.chromecast && aacCodecProfileConditions.push({ - Condition: "LessThanEqual", - Property: "AudioChannels", - Value: "2", - IsRequired: !0 - }), aacCodecProfileConditions.length && profile.CodecProfiles.push({ - Type: "VideoAudio", - Codec: "aac", - Conditions: aacCodecProfileConditions - }), supportsSecondaryAudio || profile.CodecProfiles.push({ - Type: "VideoAudio", - Conditions: [{ - Condition: "Equals", - Property: "IsSecondaryAudio", - Value: "false", - IsRequired: "false" - }] + }); }); - var maxH264Level = browser.chromecast ? 42 : 51, - h264Profiles = "high|main|baseline|constrained baseline"; - maxH264Level >= 51 && browser.chrome && !browser.osx && (h264Profiles += "|high 10"), profile.CodecProfiles.push({ - Type: "Video", - Codec: "h264", - Conditions: [{ - Condition: "NotEquals", - Property: "IsAnamorphic", - Value: "true", - IsRequired: !1 - }, { - Condition: "EqualsAny", - Property: "VideoProfile", - Value: h264Profiles - }, { - Condition: "LessThanEqual", - Property: "VideoLevel", - Value: maxH264Level.toString() - }] - }), browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s, maxVideoWidth && profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({ - Condition: "LessThanEqual", - Property: "Width", - Value: maxVideoWidth.toString(), - IsRequired: !1 + + if (canPlayMkv && !browser.tizen && !browser.orsay && options.enableMkvProgressive !== false) { + profile.TranscodingProfiles.push({ + Container: 'mkv', + Type: 'Video', + AudioCodec: videoAudioCodecs.join(','), + VideoCodec: mp4VideoCodecs.join(','), + Context: 'Streaming', + MaxAudioChannels: physicalAudioChannels.toString(), + CopyTimestamps: true + }); + } + + if (canPlayMkv) { + profile.TranscodingProfiles.push({ + Container: 'mkv', + Type: 'Video', + AudioCodec: videoAudioCodecs.join(','), + VideoCodec: mp4VideoCodecs.join(','), + Context: 'Static', + MaxAudioChannels: physicalAudioChannels.toString(), + CopyTimestamps: true + }); + } + + if (canPlayHls() && options.enableHls !== false) { + profile.TranscodingProfiles.push({ + Container: 'ts', + Type: 'Video', + AudioCodec: hlsVideoAudioCodecs.join(','), + VideoCodec: hlsVideoCodecs.join(','), + Context: 'Streaming', + Protocol: 'hls', + MaxAudioChannels: physicalAudioChannels.toString(), + MinSegments: browser.iOS || browser.osx ? '2' : '1', + BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames + }); + } + + if (canPlayVp8) { + profile.TranscodingProfiles.push({ + Container: 'webm', + Type: 'Video', + AudioCodec: 'vorbis', + VideoCodec: 'vpx', + Context: 'Streaming', + Protocol: 'http', + // If audio transcoding is needed, limit channels to number of physical audio channels + // Trying to transcode to 5 channels when there are only 2 speakers generally does not sound good + MaxAudioChannels: physicalAudioChannels.toString() + }); + } + + profile.TranscodingProfiles.push({ + Container: 'mp4', + Type: 'Video', + AudioCodec: videoAudioCodecs.join(','), + VideoCodec: 'h264', + Context: 'Static', + Protocol: 'http' }); - var globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || "").toString(), - h264MaxVideoBitrate = globalMaxVideoBitrate; - h264MaxVideoBitrate && profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({ - Condition: "LessThanEqual", - Property: "VideoBitrate", - Value: h264MaxVideoBitrate, - IsRequired: !0 + + profile.ContainerProfiles = []; + + profile.CodecProfiles = []; + + var supportsSecondaryAudio = browser.tizen || browser.orsay || videoTestElement.audioTracks; + + var aacCodecProfileConditions = []; + + // Handle he-aac not supported + if (!videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.5"').replace(/no/, '')) { + // TODO: This needs to become part of the stream url in order to prevent stream copy + aacCodecProfileConditions.push({ + Condition: 'NotEquals', + Property: 'AudioProfile', + Value: 'HE-AAC' + }); + } + + if (!supportsSecondaryAudio) { + aacCodecProfileConditions.push({ + Condition: 'Equals', + Property: 'IsSecondaryAudio', + Value: 'false', + IsRequired: 'false' + }); + } + + if (browser.chromecast) { + aacCodecProfileConditions.push({ + Condition: 'LessThanEqual', + Property: 'AudioChannels', + Value: '2', + IsRequired: true + }); + } + + if (aacCodecProfileConditions.length) { + profile.CodecProfiles.push({ + Type: 'VideoAudio', + Codec: 'aac', + Conditions: aacCodecProfileConditions + }); + } + + if (!supportsSecondaryAudio) { + profile.CodecProfiles.push({ + Type: 'VideoAudio', + Conditions: [ + { + Condition: 'Equals', + Property: 'IsSecondaryAudio', + Value: 'false', + IsRequired: 'false' + } + ] + }); + } + + var maxH264Level = browser.chromecast ? 42 : 51; + var h264Profiles = 'high|main|baseline|constrained baseline'; + + if (maxH264Level >= 51 && browser.chrome && !browser.osx) { + h264Profiles += '|high 10'; + } + + profile.CodecProfiles.push({ + Type: 'Video', + Codec: 'h264', + Conditions: [ + { + Condition: 'NotEquals', + Property: 'IsAnamorphic', + Value: 'true', + IsRequired: false + }, + { + Condition: 'EqualsAny', + Property: 'VideoProfile', + Value: h264Profiles + }, + { + Condition: 'LessThanEqual', + Property: 'VideoLevel', + Value: maxH264Level.toString() + }] }); + + if (!browser.edgeUwp && !browser.tizen && !browser.orsay && !browser.web0s) { + //profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({ + // Condition: 'NotEquals', + // Property: 'IsAVC', + // Value: 'false', + // IsRequired: false + //}); + + //profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({ + // Condition: 'NotEquals', + // Property: 'IsInterlaced', + // Value: 'true', + // IsRequired: false + //}); + } + + if (maxVideoWidth) { + profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({ + Condition: 'LessThanEqual', + Property: 'Width', + Value: maxVideoWidth.toString(), + IsRequired: false + }); + } + + var globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || '').toString(); + + var h264MaxVideoBitrate = globalMaxVideoBitrate; + + if (h264MaxVideoBitrate) { + profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({ + Condition: 'LessThanEqual', + Property: 'VideoBitrate', + Value: h264MaxVideoBitrate, + IsRequired: true + }); + } + var globalVideoConditions = []; - return globalMaxVideoBitrate && globalVideoConditions.push({ - Condition: "LessThanEqual", - Property: "VideoBitrate", - Value: globalMaxVideoBitrate - }), maxVideoWidth && globalVideoConditions.push({ - Condition: "LessThanEqual", - Property: "Width", - Value: maxVideoWidth.toString(), - IsRequired: !1 - }), globalVideoConditions.length && profile.CodecProfiles.push({ - Type: "Video", - Conditions: globalVideoConditions - }), browser.chromecast && profile.CodecProfiles.push({ - Type: "Audio", - Codec: "flac", - Conditions: [{ - Condition: "LessThanEqual", - Property: "AudioSampleRate", - Value: "96000" - }] - }), profile.SubtitleProfiles = [], supportsTextTracks() && profile.SubtitleProfiles.push({ - Format: "vtt", - Method: "External" - }), profile.ResponseProfiles = [], profile.ResponseProfiles.push({ - Type: "Video", - Container: "m4v", - MimeType: "video/mp4" - }), profile - } + + if (globalMaxVideoBitrate) { + globalVideoConditions.push({ + Condition: 'LessThanEqual', + Property: 'VideoBitrate', + Value: globalMaxVideoBitrate + }); + } + + if (maxVideoWidth) { + globalVideoConditions.push({ + Condition: 'LessThanEqual', + Property: 'Width', + Value: maxVideoWidth.toString(), + IsRequired: false + }); + } + + if (globalVideoConditions.length) { + profile.CodecProfiles.push({ + Type: 'Video', + Conditions: globalVideoConditions + }); + } + + if (browser.chromecast) { + profile.CodecProfiles.push({ + Type: 'Audio', + Codec: 'flac', + Conditions: [ + { + Condition: 'LessThanEqual', + Property: 'AudioSampleRate', + Value: '96000' + }] + }); + } + + // Subtitle profiles + // External vtt or burn in + profile.SubtitleProfiles = []; + if (supportsTextTracks()) { + + profile.SubtitleProfiles.push({ + Format: 'vtt', + Method: 'External' + }); + } + + profile.ResponseProfiles = []; + + profile.ResponseProfiles.push({ + Type: 'Video', + Container: 'm4v', + MimeType: 'video/mp4' + }); + + return profile; + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/cardbuilder/card.css b/src/bower_components/emby-webcomponents/cardbuilder/card.css index dbe41a857a..ebdeffe1df 100644 --- a/src/bower_components/emby-webcomponents/cardbuilder/card.css +++ b/src/bower_components/emby-webcomponents/cardbuilder/card.css @@ -1,23 +1,10 @@ -.card, -.card:focus { - font-weight: inherit !important -} - -.card, -.cardBox, -.cardContent, -.textActionButton { - -webkit-tap-highlight-color: transparent; - outline: 0 !important -} - button::-moz-focus-inner { padding: 0; - border: 0 + border: 0; } button { - -webkit-border-fit: border !important + -webkit-border-fit: border !important; } .card { @@ -25,155 +12,127 @@ button { font-size: inherit !important; font-family: inherit !important; text-transform: none; - background: 0 0 !important; + background-color: transparent !important; + background: none !important; margin: 0; padding: 0; display: block; color: inherit !important; + -webkit-tap-highlight-color: rgba(0,0,0,0); + outline: none !important; cursor: pointer; contain: layout style; - -webkit-flex-shrink: 0; - flex-shrink: 0 -} - -.cardContent-button, -.textActionButton { - cursor: pointer; - vertical-align: middle; - font-family: inherit + flex-shrink: 0; + font-weight: inherit !important; } .card-nofocustransform { - contain: layout style paint + contain: layout style paint; } .itemsContainer { - display: -webkit-box; - display: -webkit-flex; - display: flex -} - -.vertical-list, -.vertical-wrap { - display: -webkit-box; - display: -webkit-flex; - -webkit-box-direction: normal + display: flex; } .vertical-list { display: flex; - -webkit-box-orient: vertical; - -webkit-flex-direction: column; flex-direction: column; - -webkit-flex-wrap: nowrap; - flex-wrap: nowrap + flex-wrap: nowrap; } .vertical-wrap { display: flex; - -webkit-box-orient: horizontal; - -webkit-flex-direction: row; flex-direction: row; - -webkit-flex-wrap: wrap; - flex-wrap: wrap + flex-wrap: wrap; } -.cardImageContainer, -.mediaSourceIndicator { - display: -webkit-box; - -webkit-box-align: center -} - -.vertical-wrap.centered { - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center -} + .vertical-wrap.centered { + justify-content: center; + } .cardScalable { position: relative; - contain: layout style + contain: layout style; } -.cardPadder-backdrop, -.cardPadder-mixedBackdrop, -.cardPadder-overflowBackdrop, -.cardPadder-overflowSmallBackdrop, -.cardPadder-smallBackdrop { +.cardPadder-backdrop, .cardPadder-mixedBackdrop, .cardPadder-smallBackdrop, .cardPadder-overflowBackdrop, .cardPadder-overflowSmallBackdrop { padding-bottom: 56.25%; - contain: strict + contain: strict; } -.cardPadder-mixedSquare, -.cardPadder-overflowSquare, -.cardPadder-square, -.overflowSquareCard-textCardPadder { +.cardPadder-square, .cardPadder-mixedSquare, .cardPadder-overflowSquare, .overflowSquareCard-textCardPadder { padding-bottom: 100%; - contain: strict + contain: strict; } -.cardPadder-mixedPortrait, -.cardPadder-overflowPortrait, -.cardPadder-portrait, -.overflowPortraitCard-textCardPadder { +.cardPadder-portrait, .cardPadder-mixedPortrait, .cardPadder-overflowPortrait, .overflowPortraitCard-textCardPadder { padding-bottom: 150%; - contain: strict + contain: strict; } .cardPadder-banner { padding-bottom: 18.5%; - contain: strict + contain: strict; } .cardBox { padding: 0 !important; margin: .42em; - -webkit-transition: none; - -o-transition: none; transition: none; border: 0 solid transparent; - contain: layout style + /* These both are needed in case cardBox is a button */ + -webkit-tap-highlight-color: rgba(0,0,0,0); + outline: none !important; + contain: layout style; } -@media (min-width:50em) { +/*.cardBox-withfocuscontent { + margin: .68em; +}*/ + +@media (min-width: 50em) { + .cardBox { - margin: .9em + margin: .9em; } } .cardBox-withfocuscontent-large { - margin: .4em + margin: .4em; } +/*.card-focuscontent { + border: .12em solid transparent; +}*/ + .card-focuscontent-large { - border: .5em solid transparent + border: .5em solid transparent; } .cardBox-focustransform { will-change: transform; - -webkit-transition: -webkit-transform .2s ease-out; - -o-transition: transform .2s ease-out; - transition: transform .2s ease-out + transition: transform 200ms ease-out; } -.card:focus>.cardBox-focustransform { - -webkit-transform: scale(1.18, 1.18); - transform: scale(1.18, 1.18) +.card:focus > .cardBox-focustransform { + transform: scale(1.18, 1.18); } .cardBox-bottompadded { - margin-bottom: 1.8em !important + margin-bottom: 1.8em !important; } -@media (max-width:50em) { +@media (max-width: 50em) { + .cardBox-bottompadded { - margin-bottom: 1.2em !important + margin-bottom: 1.2em !important; } } .card:focus { position: relative !important; - z-index: 10 !important + z-index: 10 !important; + font-weight: inherit !important; } .btnCardOptions { @@ -181,17 +140,13 @@ button { bottom: .25em; right: 0; margin: 0 !important; - z-index: 1 + z-index: 1; } .mediaSourceIndicator { - display: -webkit-flex; display: flex; position: absolute; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; top: .3em; left: .3em; @@ -199,186 +154,178 @@ button { vertical-align: middle; width: 1.6em; height: 1.6em; - -webkit-border-radius: 50%; border-radius: 50%; color: #fff; - background: #38c -} - -.cardText, -.innerCardFooter { - overflow: hidden; - text-align: left + background: rgb(51, 136, 204); } .cardImageContainer { - -webkit-background-size: contain; background-size: contain; background-repeat: no-repeat; background-position: center center; - -webkit-align-items: center; + display: -webkit-flex; + display: flex; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; position: relative; - -webkit-background-clip: content-box !important; background-clip: content-box !important; color: inherit; + /* This is only needed for scalable cards */ height: 100%; - contain: strict -} - -.cardContent, -.cardImage { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0 + contain: strict; } .chapterCardImageContainer { background-color: #000; - -webkit-border-radius: 0; - border-radius: 0 + border-radius: 0; } .textCardImageContainer { - background-color: #333 + background-color: #333; } .cardContent { overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + /* Needed in case this is a button */ display: block; + /* Needed in case this is a button */ margin: 0 !important; + /* Needed in safari */ height: 100%; - contain: strict + -webkit-tap-highlight-color: rgba(0,0,0,0); + outline: none !important; + contain: strict; } .cardContent-button { border: 0 !important; padding: 0 !important; + cursor: pointer; color: inherit; width: 100%; - font-size: inherit + vertical-align: middle; + font-family: inherit; + font-size: inherit; } -.cardContent-button:not(.defaultCardBackground) { - background-color: transparent -} + .cardContent-button:not(.defaultCardBackground) { + background-color: transparent; + } .visualCardBox .cardContent { - -webkit-border-bottom-left-radius: 0; border-bottom-left-radius: 0; - -webkit-border-bottom-right-radius: 0; - border-bottom-right-radius: 0 + border-bottom-right-radius: 0; } .cardContent-shadow { - -webkit-box-shadow: 0 .0725em .29em 0 rgba(0, 0, 0, .37); - box-shadow: 0 .0725em .29em 0 rgba(0, 0, 0, .37) + box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); } +/*.card:focus .cardContent-shadow { + box-shadow: 0 .63em 1.26em rgba(0, 0, 0, 0.37); +}*/ + .cardImageContainer { - display: -webkit-box; - display: -webkit-flex; - display: flex + display: flex; } .cardImage { - -webkit-background-size: contain; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; background-size: contain; background-repeat: no-repeat; - background-position: center bottom + background-position: center bottom; } .cardImage-img { max-height: 100%; max-width: 100%; + /* This is simply for lazy image purposes, to ensure the image is visible sooner when scrolling */ min-height: 70%; min-width: 70%; - margin: auto + margin: auto; } .coveredImage-img { width: 100%; - height: 100% + height: 100%; } .coveredImage-noscale-img { max-height: none; - max-width: none + max-width: none; } .coveredImage { - -webkit-background-size: 100% 100%; background-size: 100% 100%; - background-position: center center + background-position: center center; } .coveredImage-noScale { - -webkit-background-size: cover; - background-size: cover + background-size: cover; } .cardFooter { - padding: .3em .3em .5em; - position: relative + padding: .3em .3em .5em .3em; + position: relative; } .visualCardBox { - -webkit-box-shadow: 0 .0725em .29em 0 rgba(0, 0, 0, .37); - box-shadow: 0 .0725em .29em 0 rgba(0, 0, 0, .37); - -webkit-border-radius: .145em; - border-radius: .145em + box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); + border-radius: .145em; } .innerCardFooter { - background: rgba(0, 0, 0, .7); + background: rgba(0,0,0,.7); position: absolute; bottom: 0; left: 0; + text-align: left; z-index: 1; + overflow: hidden; max-width: 100%; - color: #fff + color: #fff; } .innerCardFooterClear { - background-color: transparent + background-color: transparent; } .fullInnerCardFooter { - right: 0 + right: 0; } .cardText { padding: .06em .5em; white-space: nowrap; - -o-text-overflow: ellipsis; - text-overflow: ellipsis -} - -.cardDefaultText, -.cardTextCentered { - text-align: center + overflow: hidden; + text-overflow: ellipsis; + text-align: left; } .cardText-secondary { - font-size: 86% + font-size: 86%; } .cardText-first { - padding-top: .24em + padding-top: .24em; } -.innerCardFooter>.cardText { - padding: .3em .5em +.innerCardFooter > .cardText { + padding: .3em .5em; } .cardFooter-withlogo { padding-left: 4em; - position: relative + position: relative; } .cardFooterLogo { @@ -387,70 +334,77 @@ button { bottom: 0; left: 0; width: 4.5em; - -webkit-background-size: 70% auto; background-size: 70% auto; background-repeat: no-repeat; - background-position: center center + background-position: center center; +} + +.cardTextCentered { + text-align: center; } .cardText-rightmargin { - margin-right: 2em + margin-right: 2em; } .cardDefaultText { - white-space: normal + white-space: normal; + text-align: center; } .textActionButton { - background: 0 0; + border: 0 !important; + background: transparent; border: 0 !important; padding: 0 !important; + cursor: pointer; + -webkit-tap-highlight-color: rgba(0,0,0,0); + outline: none !important; color: inherit; - font-size: inherit + vertical-align: middle; + font-family: inherit; + font-size: inherit; + /*display: flex; + align-items: center; + justify-content: center;*/ } -.textActionButton:hover { - text-decoration: underline -} + .textActionButton:hover { + text-decoration: underline; + } .cardImageIcon { font-size: 5em; - color: inherit + color: inherit; } .cardImageIcon-small { font-size: 3em; - margin-bottom: .1em + margin-bottom: .1em; } .cardIndicators { right: .225em; top: .225em; position: absolute; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - contain: layout style + contain: layout style; } .cardProgramAttributeIndicators { top: 0; left: 0; position: absolute; - display: -webkit-box; - display: -webkit-flex; display: flex; text-transform: uppercase; - font-size: 92% + font-size: 92%; } .programAttributeIndicator { padding: .18em .5em; color: #fff; - font-weight: 500 + font-weight: 500; } .cardOverlayButton { @@ -458,31 +412,24 @@ button { margin: 0; z-index: 1; padding: .75em; - font-size: 88% + font-size: 88%; } .cardOverlayButton-br { position: absolute; bottom: 0; - right: 0 + right: 0; } .cardOverlayButtonIcon { - background-color: rgba(0, 0, 0, .7) !important; - -webkit-border-radius: 100em; + background-color: rgba(0,0,0,.7) !important; border-radius: 100em; width: 1.5em !important; height: 1.5em !important; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - display: -webkit-box; - display: -webkit-flex; display: flex; - font-size: 1.66956521739130434em !important + font-size: 1.66956521739130434em !important; } .cardOverlayButton-centered { @@ -490,8 +437,6 @@ button { right: initial; position: static; position: absolute; - display: -webkit-box; - display: -webkit-flex; display: flex; font-size: 112%; margin: -1.3em 0 0 -1.3em; @@ -499,372 +444,358 @@ button { height: 2.6em; top: 50%; left: 50%; - background-color: rgba(0, 0, 0, .5) !important; - border: .06em solid rgba(255, 255, 255, .6); + background-color: rgba(0,0,0,.5) !important; + border: .06em solid rgba(255,255,255,.6); padding: .38em !important; color: rgba(255, 255, 255, .76); - -webkit-transition: -webkit-transform .2s ease-out; - -o-transition: transform .2s ease-out; - transition: transform .2s ease-out + transition: transform 200ms ease-out; } -.cardOverlayButton-centered:hover { - -webkit-transform: scale(1.2, 1.2); - transform: scale(1.2, 1.2) -} + .cardOverlayButton-centered:hover { + transform: scale(1.2, 1.2); + } -.backdropCard, .bannerCard { - width: 100% + width: 100%; +} + +.backdropCard { + width: 100%; +} + +.smallBackdropCard { + width: 50%; } -.smallBackdropCard, .squareCard { - width: 50% + width: 50%; } .portraitCard { - width: 33.333333333333333333333333333333% + width: 33.333333333333333333333333333333%; } .mixedPortraitCard { - width: 12em + width: 12em; } .mixedSquareCard { - width: 18em + width: 18em; } .mixedBackdropCard { - width: 32em + width: 32em; } -@media (min-width:25em) { +@media (min-width: 25em) { + .backdropCard { - width: 50% + width: 50%; } } -@media (min-width:31.25em) { +@media (min-width: 31.25em) { - .portraitCard, - .smallBackdropCard, - .squareCard { - width: 33.333333333333333333333333333333% + .smallBackdropCard { + width: 33.333333333333333333333333333333%; + } + + .squareCard, .portraitCard { + width: 33.333333333333333333333333333333%; } } -@media (min-width:43.75em) { - - .portraitCard, - .squareCard { - width: 25% +@media (min-width: 43.75em) { + .squareCard, .portraitCard { + width: 25%; } } -@media (min-width:48.125em) { +@media (min-width: 48.125em) { .backdropCard { - width: 33.333333333333333333333333333333% + width: 33.333333333333333333333333333333%; } } -@media (min-width:50em) { +@media (min-width: 50em) { + .bannerCard { - width: 50% + width: 50%; } - .portraitCard, - .squareCard { - width: 20% + .squareCard, .portraitCard { + width: 20%; } .smallBackdropCard { - width: 25% + width: 25%; } } -@media (min-width:62.5em) { +@media (min-width: 62.5em) { + + .smallBackdropCard { - width: 20% + width: 20%; } } -@media (min-width:75em) { +@media (min-width: 75em) { + .backdropCard { - width: 25% + width: 25%; } - .portraitCard, - .squareCard { - width: 16.666666666666666666666666666667% + .squareCard, .portraitCard { + width: 16.666666666666666666666666666667%; } .bannerCard { - width: 33.333333333333333333333333333333% + width: 33.333333333333333333333333333333%; } .smallBackdropCard { - width: 16.666666666666666666666666666667% + width: 16.666666666666666666666666666667%; } } -@media (min-width:87.5em) { - .portraitCard, - .smallBackdropCard, - .squareCard { - width: 14.285714285714285714285714285714% +@media (min-width: 87.5em) { + + .squareCard, .portraitCard { + width: 14.285714285714285714285714285714%; } -} -@media (min-width:100em) { .smallBackdropCard { - width: 12.5% + width: 14.285714285714285714285714285714%; + } +} + +@media (min-width: 100em) { + + .smallBackdropCard { + width: 12.5%; } .backdropCard { - width: 20% + width: 20%; } - .portraitCard, - .squareCard { - width: 12.5% + .squareCard, .portraitCard { + width: 12.5%; } } -@media (min-width:120em) { +@media (min-width: 120em) { - .portraitCard, - .squareCard { - width: 11.111111111111111111111111111111% + .squareCard, .portraitCard { + width: 11.111111111111111111111111111111%; } } -@media (min-width:131.25em) { +@media (min-width: 131.25em) { + .bannerCard { - width: 25% + width: 25%; } - .portraitCard, - .squareCard { - width: 10% + .squareCard, .portraitCard { + width: 10%; } } -@media (min-width:156.25em) { +@media (min-width: 156.25em) { + .backdropCard { - width: 16.666666666666666666666666666667% + width: 16.666666666666666666666666666667%; } } -.itemsContainer-tv>.backdropCard { - width: 25% +.itemsContainer-tv > .backdropCard { + width: 25%; } -.itemsContainer-tv>.portraitCard, -.itemsContainer-tv>.squareCard { - width: 16.666666666666666666666666666667% +.itemsContainer-tv > .squareCard { + width: 16.666666666666666666666666666667%; +} + +.itemsContainer-tv > .portraitCard { + width: 16.666666666666666666666666666667%; +} + +.overflowBackdropCard { + width: 72vw; } -.overflowBackdropCard, .overflowSmallBackdropCard { - width: 72vw + width: 72vw; } -.overflowPortraitCard, -.overflowSquareCard { - width: 40vw +.overflowSquareCard, .overflowPortraitCard { + width: 40vw; } -@media (min-width:25em) { +@media (min-width: 25em) { .overflowPortraitCard { - width: 31.2vw + width: 31.2vw; } } -@media (min-width:35em) { +@media (min-width: 35em) { .overflowSquareCard { - width: 31.2vw + width: 31.2vw; } .overflowBackdropCard { - width: 45.5vw + width: 45.5vw; } .overflowSmallBackdropCard { - width: 30vw + width: 30vw; } } -@media (min-width:43.75em) { - - .overflowPortraitCard, - .overflowSquareCard { - width: 23.3vw +@media (min-width: 43.75em) { + .overflowSquareCard, .overflowPortraitCard { + width: 23.3vw; } } -@media (min-width:48.125em) { +@media (min-width: 48.125em) { + .overflowBackdropCard, .overflowSmallBackdropCard { + width: 30vw; + } +} - .overflowBackdropCard, +@media (orientation: landscape) { + .overflowBackdropCard, .overflowSmallBackdropCard { + width: 30vw; + } + + .overflowSquareCard, .overflowPortraitCard { + width: 23.3vw; + } +} + +@media (orientation: landscape) and (min-width: 48.125em) { + .overflowBackdropCard, .overflowSmallBackdropCard { + width: 23.3vw; + } +} + +@media (orientation: landscape) and (min-width: 50em) { .overflowSmallBackdropCard { - width: 30vw + width: 15.5vw; } } -@media (orientation:landscape) { +@media (min-width: 50em) { - .overflowBackdropCard, - .overflowSmallBackdropCard { - width: 30vw - } - - .overflowPortraitCard, - .overflowSquareCard { - width: 23.3vw + .overflowSquareCard, .overflowPortraitCard { + width: 18.4vw; } } -@media (orientation:landscape) and (min-width:48.125em) { +@media (min-width: 75em) { - .overflowBackdropCard, - .overflowSmallBackdropCard { - width: 23.3vw + .overflowBackdropCard, .overflowSmallBackdropCard { + width: 23.3vw; + } + + .overflowSquareCard, .overflowPortraitCard { + width: 15.5vw; } } -@media (orientation:landscape) and (min-width:50em) { - .overflowSmallBackdropCard { - width: 15.5vw +@media (min-width: 87.5em) { + + .overflowSquareCard, .overflowPortraitCard { + width: 13.3vw; } } -@media (min-width:50em) { +@media (min-width: 100em) { - .overflowPortraitCard, - .overflowSquareCard { - width: 18.4vw + .overflowBackdropCard, .overflowSmallBackdropCard { + width: 18.7vw; + } + + .overflowSquareCard, .overflowPortraitCard { + width: 11.6vw; } } -@media (min-width:75em) { +@media (min-width: 120em) { - .overflowBackdropCard, - .overflowSmallBackdropCard { - width: 23.3vw - } - - .overflowPortraitCard, - .overflowSquareCard { - width: 15.5vw + .overflowSquareCard, .overflowPortraitCard { + width: 10.3vw; } } -@media (min-width:87.5em) { +@media (min-width: 131.25em) { - .overflowPortraitCard, - .overflowSquareCard { - width: 13.3vw + .overflowSquareCard, .overflowPortraitCard { + width: 9.3vw; } } -@media (min-width:100em) { +@media (min-width: 156.25em) { - .overflowBackdropCard, - .overflowSmallBackdropCard { - width: 18.7vw - } - - .overflowPortraitCard, - .overflowSquareCard { - width: 11.6vw + .overflowBackdropCard, .overflowSmallBackdropCard { + width: 15.6vw; } } -@media (min-width:120em) { - - .overflowPortraitCard, - .overflowSquareCard { - width: 10.3vw - } -} - -@media (min-width:131.25em) { - - .overflowPortraitCard, - .overflowSquareCard { - width: 9.3vw - } -} - -@media (min-width:156.25em) { - - .overflowBackdropCard, - .overflowSmallBackdropCard { - width: 15.6vw - } -} - -.itemsContainer-tv>.overflowBackdropCard { - width: 23.5vw +.itemsContainer-tv > .overflowBackdropCard { + width: 23.5vw; } .overflowBackdropCard-textCard { - width: 15.5vw !important + width: 15.5vw !important; } .overflowBackdropCard-textCardPadder { - padding-bottom: 87.75% + padding-bottom: 87.75%; } -.itemsContainer-tv>.overflowPortraitCard, -.itemsContainer-tv>.overflowSquareCard { - width: 15.6vw +.itemsContainer-tv > .overflowSquareCard, .itemsContainer-tv > .overflowPortraitCard { + width: 15.6vw; } -.itemsContainer-tv>.overflowSmallBackdropCard { - width: 18.8vw +.itemsContainer-tv > .overflowSmallBackdropCard { + width: 18.8vw; } .cardOverlayContainer { - background: -webkit-radial-gradient(50% 50%, farthest-corner, rgba(30, 30, 30, .5) 50%, #2c2c2c 100%); - background: -o-radial-gradient(50% 50%, farthest-corner, rgba(30, 30, 30, .5) 50%, #2c2c2c 100%); - background: radial-gradient(farthest-corner at 50% 50%, rgba(30, 30, 30, .5) 50%, #2c2c2c 100%); + background: radial-gradient(farthest-corner at 50% 50%,rgba(30,30,30,.5) 50%,#2c2c2c 100%); opacity: 0; - -webkit-transition: opacity .2s; - -o-transition: opacity .2s; transition: opacity .2s; position: absolute; top: 0; left: 0; bottom: 0; right: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none + user-select: none; } .card-hoverable :hover .cardOverlayContainer { - opacity: 1 + opacity: 1; } .cardOverlayButton-hover { opacity: 0; - -webkit-transition: opacity .2s; - -o-transition: opacity .2s; transition: opacity .2s; - background: 0 0; + background: transparent; color: #fff !important; - padding: .5em + padding: .5em; } .cardOverlayButtonIcon-hover { - background: 0 0 !important + background: transparent !important; } .card-hoverable:hover .cardOverlayButton-hover { - opacity: 1 + opacity: 1; } .cardOverlayFab-primary { @@ -876,10 +807,10 @@ button { margin-left: -1.5em; position: absolute; top: 50%; - left: 50% + left: 50%; } -.cardOverlayFab-primary i { - border: .07em solid rgba(255, 255, 255, .9); - color: #fff -} \ No newline at end of file + .cardOverlayFab-primary i { + border: .07em solid rgba(255,255,255,.9); + color: #fff; + } diff --git a/src/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js b/src/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js index ffb42171bc..439c8227a3 100644 --- a/src/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js +++ b/src/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js @@ -1,515 +1,1818 @@ -define(["datetime", "imageLoader", "connectionManager", "itemHelper", "focusManager", "indicators", "globalize", "layoutManager", "apphost", "dom", "browser", "playbackManager", "itemShortcuts", "css!./card", "paper-icon-button-light", "programStyles"], function(datetime, imageLoader, connectionManager, itemHelper, focusManager, indicators, globalize, layoutManager, appHost, dom, browser, playbackManager, itemShortcuts) { - "use strict"; +define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusManager', 'indicators', 'globalize', 'layoutManager', 'apphost', 'dom', 'browser', 'playbackManager', 'itemShortcuts', 'css!./card', 'paper-icon-button-light', 'programStyles'], + function (datetime, imageLoader, connectionManager, itemHelper, focusManager, indicators, globalize, layoutManager, appHost, dom, browser, playbackManager, itemShortcuts) { + 'use strict'; - function getCardsHtml(items, options) { - return 1 === arguments.length && (options = arguments[0], items = options.items), buildCardsHtmlInternal(items, options) - } + var devicePixelRatio = window.devicePixelRatio || 1; + var enableFocusTransfrom = !browser.slow && !browser.edge; - function getPostersPerRow(shape, screenWidth, isOrientationLandscape) { - switch (shape) { - case "portrait": - return layoutManager.tv ? 5.9999999988 : screenWidth >= 2200 ? 10 : screenWidth >= 1920 ? 9.000000000009 : screenWidth >= 1600 ? 8 : screenWidth >= 1400 ? 7.0000000000021 : screenWidth >= 1200 ? 5.9999999988 : screenWidth >= 800 ? 5 : screenWidth >= 700 ? 4 : 3.0000000003; - case "square": - return layoutManager.tv ? 5.9999999988 : screenWidth >= 2200 ? 10 : screenWidth >= 1920 ? 9.000000000009 : screenWidth >= 1600 ? 8 : screenWidth >= 1400 ? 7.0000000000021 : screenWidth >= 1200 ? 5.9999999988 : screenWidth >= 800 ? 5 : screenWidth >= 700 ? 4 : screenWidth >= 500 ? 3.0000000003 : 2; - case "banner": - return screenWidth >= 2200 ? 4 : screenWidth >= 1200 ? 3.0000000003 : screenWidth >= 800 ? 2 : 1; - case "backdrop": - return layoutManager.tv ? 4 : screenWidth >= 2500 ? 6 : screenWidth >= 1600 ? 5 : screenWidth >= 1200 ? 4 : screenWidth >= 770 ? 3 : screenWidth >= 420 ? 2 : 1; - case "smallBackdrop": - return screenWidth >= 1600 ? 8 : screenWidth >= 1400 ? 7.000000000007001 : screenWidth >= 1200 ? 6 : screenWidth >= 1e3 ? 5 : screenWidth >= 800 ? 4 : screenWidth >= 500 ? 3.0000000003 : 2; - case "overflowSmallBackdrop": - return layoutManager.tv ? 100 / 18.9 : isOrientationLandscape ? screenWidth >= 800 ? 100 / 15.5 : 100 / 23.3 : screenWidth >= 540 ? 100 / 30 : 100 / 72; - case "overflowPortrait": - return layoutManager.tv ? 100 / 15.5 : isOrientationLandscape ? screenWidth >= 1700 ? 100 / 11.6 : 100 / 15.5 : screenWidth >= 1400 ? 100 / 15 : screenWidth >= 1200 ? 100 / 18 : screenWidth >= 760 ? 100 / 23 : screenWidth >= 400 ? 100 / 31.5 : 100 / 42; - case "overflowSquare": - return layoutManager.tv ? 100 / 15.5 : isOrientationLandscape ? screenWidth >= 1700 ? 100 / 11.6 : 100 / 15.5 : screenWidth >= 1400 ? 100 / 15 : screenWidth >= 1200 ? 100 / 18 : screenWidth >= 760 ? 100 / 23 : screenWidth >= 540 ? 100 / 31.5 : 100 / 42; - case "overflowBackdrop": - return layoutManager.tv ? 100 / 23.3 : isOrientationLandscape ? screenWidth >= 1700 ? 100 / 18.5 : 100 / 23.3 : screenWidth >= 1800 ? 100 / 23.5 : screenWidth >= 1400 ? 100 / 30 : screenWidth >= 760 ? 2.5 : screenWidth >= 640 ? 100 / 56 : 100 / 72; - default: - return 4 - } - } + function getCardsHtml(items, options) { - function isResizable(windowWidth) { - var screen = window.screen; - if (screen) { - if (screen.availWidth - windowWidth > 20) return !0 - } - return !1 - } + if (arguments.length === 1) { - function getImageWidth(shape, screenWidth, isOrientationLandscape) { - var imagesPerRow = getPostersPerRow(shape, screenWidth, isOrientationLandscape), - shapeWidth = screenWidth / imagesPerRow; - return Math.round(shapeWidth) - } - - function setCardData(items, options) { - options.shape = options.shape || "auto"; - var primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items); - if ("auto" === options.shape || "autohome" === options.shape || "autooverflow" === options.shape || "autoVertical" === options.shape) { - var requestedShape = options.shape; - options.shape = null, primaryImageAspectRatio && (primaryImageAspectRatio >= 3 ? (options.shape = "banner", options.coverImage = !0) : options.shape = primaryImageAspectRatio >= 1.33 ? "autooverflow" === requestedShape ? "overflowBackdrop" : "backdrop" : primaryImageAspectRatio > .71 ? "autooverflow" === requestedShape ? "overflowSquare" : "square" : "autooverflow" === requestedShape ? "overflowPortrait" : "portrait"), options.shape || (options.shape = options.defaultShape || ("autooverflow" === requestedShape ? "overflowSquare" : "square")) - } - if ("auto" === options.preferThumb && (options.preferThumb = "backdrop" === options.shape || "overflowBackdrop" === options.shape), options.uiAspect = getDesiredAspect(options.shape), options.primaryImageAspectRatio = primaryImageAspectRatio, !options.width && options.widths && (options.width = options.widths[options.shape]), options.rows && "number" != typeof options.rows && (options.rows = options.rows[options.shape]), !options.width) { - var screenWidth = dom.getWindowSize().innerWidth, - screenHeight = dom.getWindowSize().innerHeight; - if (isResizable(screenWidth)) { - screenWidth = 100 * Math.floor(screenWidth / 100) + options = arguments[0]; + items = options.items; } - options.width = getImageWidth(options.shape, screenWidth, screenWidth > 1.3 * screenHeight) - } - } - function buildCardsHtmlInternal(items, options) { - var isVertical; - "autoVertical" === options.shape && (isVertical = !0), setCardData(items, options); - var currentIndexValue, hasOpenRow, hasOpenSection, apiClient, lastServerId, i, length, html = "", - itemsInRow = 0, - sectionTitleTagName = options.sectionTitleTagName || "div"; - for (i = 0, length = items.length; i < length; i++) { - var item = items[i], - serverId = item.ServerId || options.serverId; - if (serverId !== lastServerId && (lastServerId = serverId, apiClient = connectionManager.getApiClient(lastServerId)), options.indexBy) { - var newIndexValue = ""; - if ("PremiereDate" === options.indexBy) { - if (item.PremiereDate) try { - newIndexValue = datetime.toLocaleDateString(datetime.parseISO8601Date(item.PremiereDate), { - weekday: "long", - month: "long", - day: "numeric" - }) - } catch (err) {} - } else "ProductionYear" === options.indexBy ? newIndexValue = item.ProductionYear : "CommunityRating" === options.indexBy && (newIndexValue = item.CommunityRating ? Math.floor(item.CommunityRating) + (item.CommunityRating % 1 >= .5 ? .5 : 0) + "+" : null); - newIndexValue !== currentIndexValue && (hasOpenRow && (html += "
", hasOpenRow = !1, itemsInRow = 0), hasOpenSection && (html += "
", isVertical && (html += ""), hasOpenSection = !1), html += isVertical ? '
' : '
', html += "<" + sectionTitleTagName + ' class="sectionTitle">' + newIndexValue + "", isVertical && (html += '
'), currentIndexValue = newIndexValue, hasOpenSection = !0) - } - options.rows && 0 === itemsInRow && (hasOpenRow && (html += "
", hasOpenRow = !1), html += '
', hasOpenRow = !0), html += buildCard(i, item, apiClient, options), itemsInRow++, options.rows && itemsInRow >= options.rows && (html += "
", hasOpenRow = !1, itemsInRow = 0) - } - hasOpenRow && (html += "
"), hasOpenSection && (html += "
", isVertical && (html += "")); - var cardFooterHtml = ""; - for (i = 0, length = options.lines || 0; i < length; i++) cardFooterHtml += 0 === i ? '
 
' : '
 
'; - return html - } - - function getDesiredAspect(shape) { - if (shape) { - if (shape = shape.toLowerCase(), -1 !== shape.indexOf("portrait")) return 2 / 3; - if (-1 !== shape.indexOf("backdrop")) return 16 / 9; - if (-1 !== shape.indexOf("square")) return 1; - if (-1 !== shape.indexOf("banner")) return 1e3 / 185 - } - return null - } - - function getCardImageUrl(item, apiClient, options, shape) { - item = item.ProgramInfo || item; - var width = options.width, - height = null, - primaryImageAspectRatio = item.PrimaryImageAspectRatio, - forceName = !1, - imgUrl = null, - coverImage = !1, - uiAspect = null; - return options.preferThumb && item.ImageTags && item.ImageTags.Thumb ? imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", - maxWidth: width, - tag: item.ImageTags.Thumb - }) : (options.preferBanner || "banner" === shape) && item.ImageTags && item.ImageTags.Banner ? imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Banner", - maxWidth: width, - tag: item.ImageTags.Banner - }) : options.preferDisc && item.ImageTags && item.ImageTags.Disc ? imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Disc", - maxWidth: width, - tag: item.ImageTags.Disc - }) : options.preferLogo && item.ImageTags && item.ImageTags.Logo ? imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Logo", - maxWidth: width, - tag: item.ImageTags.Logo - }) : options.preferLogo && item.ParentLogoImageTag && item.ParentLogoItemId ? imgUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, { - type: "Logo", - maxWidth: width, - tag: item.ParentLogoImageTag - }) : options.preferThumb && item.SeriesThumbImageTag && !1 !== options.inheritThumb ? imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { - type: "Thumb", - maxWidth: width, - tag: item.SeriesThumbImageTag - }) : options.preferThumb && item.ParentThumbItemId && !1 !== options.inheritThumb && "Photo" !== item.MediaType ? imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { - type: "Thumb", - maxWidth: width, - tag: item.ParentThumbImageTag - }) : options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length ? (imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", - maxWidth: width, - tag: item.BackdropImageTags[0] - }), forceName = !0) : options.preferThumb && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && !1 !== options.inheritThumb && "Episode" === item.Type ? imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { - type: "Backdrop", - maxWidth: width, - tag: item.ParentBackdropImageTags[0] - }) : item.ImageTags && item.ImageTags.Primary ? (height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null, imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Primary", - maxHeight: height, - maxWidth: width, - tag: item.ImageTags.Primary - }), options.preferThumb && !1 !== options.showTitle && (forceName = !0), primaryImageAspectRatio && (uiAspect = getDesiredAspect(shape)) && (coverImage = Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect <= .2)) : item.PrimaryImageTag ? (height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null, imgUrl = apiClient.getScaledImageUrl(item.PrimaryImageItemId || item.Id || item.ItemId, { - type: "Primary", - maxHeight: height, - maxWidth: width, - tag: item.PrimaryImageTag - }), options.preferThumb && !1 !== options.showTitle && (forceName = !0), primaryImageAspectRatio && (uiAspect = getDesiredAspect(shape)) && (coverImage = Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect <= .2)) : item.ParentPrimaryImageTag ? imgUrl = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, { - type: "Primary", - maxWidth: width, - tag: item.ParentPrimaryImageTag - }) : item.SeriesPrimaryImageTag ? imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { - type: "Primary", - maxWidth: width, - tag: item.SeriesPrimaryImageTag - }) : item.AlbumId && item.AlbumPrimaryImageTag ? (width = primaryImageAspectRatio ? Math.round(height * primaryImageAspectRatio) : null, imgUrl = apiClient.getScaledImageUrl(item.AlbumId, { - type: "Primary", - maxHeight: height, - maxWidth: width, - tag: item.AlbumPrimaryImageTag - }), primaryImageAspectRatio && (uiAspect = getDesiredAspect(shape)) && (coverImage = Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect <= .2)) : "Season" === item.Type && item.ImageTags && item.ImageTags.Thumb ? imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", - maxWidth: width, - tag: item.ImageTags.Thumb - }) : item.BackdropImageTags && item.BackdropImageTags.length ? imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", - maxWidth: width, - tag: item.BackdropImageTags[0] - }) : item.ImageTags && item.ImageTags.Thumb ? imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", - maxWidth: width, - tag: item.ImageTags.Thumb - }) : item.SeriesThumbImageTag && !1 !== options.inheritThumb ? imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { - type: "Thumb", - maxWidth: width, - tag: item.SeriesThumbImageTag - }) : item.ParentThumbItemId && !1 !== options.inheritThumb ? imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { - type: "Thumb", - maxWidth: width, - tag: item.ParentThumbImageTag - }) : item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && !1 !== options.inheritThumb && (imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { - type: "Backdrop", - maxWidth: width, - tag: item.ParentBackdropImageTags[0] - })), { - imgUrl: imgUrl, - forceName: forceName, - coverImage: coverImage - } - } - - function getRandomInt(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min - } - - function getDefaultColorIndex(str) { - if (str) { - for (var charIndex = Math.floor(str.length / 2), character = String(str.substr(charIndex, 1).charCodeAt()), sum = 0, i = 0; i < character.length; i++) sum += parseInt(character.charAt(i)); - return String(sum).substr(-1) % numRandomColors + 1 - } - return getRandomInt(1, numRandomColors) - } - - function getCardTextLines(lines, cssClass, forceLines, isOuterFooter, cardLayout, addRightMargin, maxLines) { - var i, length, html = "", - valid = 0; - for (i = 0, length = lines.length; i < length; i++) { - var currentCssClass = cssClass, - text = lines[i]; - if (valid > 0 && isOuterFooter ? currentCssClass += " cardText-secondary" : 0 === valid && isOuterFooter && (currentCssClass += " cardText-first"), addRightMargin && (currentCssClass += " cardText-rightmargin"), text && (html += "
", html += text, html += "
", valid++, maxLines && valid >= maxLines)) break - } - if (forceLines) - for (length = maxLines || Math.min(lines.length, maxLines || lines.length); valid < length;) html += "
 
", valid++; - return html - } - - function isUsingLiveTvNaming(item) { - return "Program" === item.Type || "Timer" === item.Type || "Recording" === item.Type - } - - function getAirTimeText(item, showAirDateTime, showAirEndTime) { - var airTimeText = ""; - if (item.StartDate) try { - var date = datetime.parseISO8601Date(item.StartDate); - showAirDateTime && (airTimeText += datetime.toLocaleDateString(date, { - weekday: "short", - month: "short", - day: "numeric" - }) + " "), airTimeText += datetime.getDisplayTime(date), item.EndDate && showAirEndTime && (date = datetime.parseISO8601Date(item.EndDate), airTimeText += " - " + datetime.getDisplayTime(date)) - } catch (e) { - console.log("Error parsing date: " + item.StartDate) - } - return airTimeText - } - - function getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerClass, progressHtml, logoUrl, isOuterFooter) { - var html = ""; - logoUrl && (html += ''); - var showOtherText = isOuterFooter ? !overlayText : overlayText; - isOuterFooter && options.cardLayout && layoutManager.mobile && "none" !== options.cardFooterAside && (html += ''); - var titleAdded, cssClass = options.centerText ? "cardText cardTextCentered" : "cardText", - lines = [], - parentTitleUnderneath = "MusicAlbum" === item.Type || "Audio" === item.Type || "MusicVideo" === item.Type; - if (showOtherText && (options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) - if (isOuterFooter && "Episode" === item.Type && item.SeriesName) item.SeriesId ? lines.push(getTextActionButton({ - Id: item.SeriesId, - ServerId: item.ServerId, - Name: item.SeriesName, - Type: "Series", - IsFolder: !0 - })) : lines.push(item.SeriesName); - else if (isUsingLiveTvNaming(item)) lines.push(item.Name), item.EpisodeTitle || (titleAdded = !0); - else { - var parentTitle = item.SeriesName || item.Series || item.Album || item.AlbumArtist || item.GameSystem || ""; - (parentTitle || showTitle) && lines.push(parentTitle) - } - var showMediaTitle = showTitle && !titleAdded || options.showParentTitleOrTitle && !lines.length; - if (showMediaTitle || titleAdded || !showTitle && !forceName || (showMediaTitle = !0), showMediaTitle) { - var name = "auto" !== options.showTitle || item.IsFolder || "Photo" !== item.MediaType ? itemHelper.getDisplayName(item, { - includeParentInfo: options.includeParentInfoInTitle - }) : ""; - lines.push(name) - } - if (showOtherText) { - if (options.showParentTitle && parentTitleUnderneath && (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length ? (item.AlbumArtists[0].Type = "MusicArtist", item.AlbumArtists[0].IsFolder = !0, lines.push(getTextActionButton(item.AlbumArtists[0], null, item.ServerId))) : lines.push(isUsingLiveTvNaming(item) ? item.Name : item.SeriesName || item.Series || item.Album || item.AlbumArtist || item.GameSystem || "")), options.showItemCounts) { - var itemCountHtml = getItemCountsHtml(options, item); - lines.push(itemCountHtml) - } - if (options.textLines) - for (var additionalLines = options.textLines(item), i = 0, length = additionalLines.length; i < length; i++) lines.push(additionalLines[i]); - if (options.showSongCount) { - var songLine = ""; - item.SongCount && (songLine = 1 === item.SongCount ? globalize.translate("sharedcomponents#ValueOneSong") : globalize.translate("sharedcomponents#ValueSongCount", item.SongCount)), lines.push(songLine) - } - if (options.showPremiereDate) - if (item.PremiereDate) try { - lines.push(getPremiereDateText(item)) - } catch (err) { - lines.push("") - } else lines.push(""); - (options.showYear || options.showSeriesYear) && ("Series" === item.Type ? "Continuing" === item.Status ? lines.push(globalize.translate("sharedcomponents#SeriesYearToPresent", item.ProductionYear || "")) : item.EndDate && item.ProductionYear ? lines.push(item.ProductionYear + " - " + datetime.parseISO8601Date(item.EndDate).getFullYear()) : lines.push(item.ProductionYear || "") : lines.push(item.ProductionYear || "")), options.showRuntime && (item.RunTimeTicks ? lines.push(datetime.getDisplayRunningTime(item.RunTimeTicks)) : lines.push("")), options.showAirTime && lines.push(getAirTimeText(item, options.showAirDateTime, options.showAirEndTime) || ""), options.showChannelName && (item.ChannelId ? lines.push(getTextActionButton({ - Id: item.ChannelId, - ServerId: item.ServerId, - Name: item.ChannelName, - Type: "TvChannel", - MediaType: item.MediaType, - IsFolder: !1 - }, item.ChannelName)) : lines.push(item.ChannelName || " ")), options.showCurrentProgram && "TvChannel" === item.Type && (item.CurrentProgram ? lines.push(item.CurrentProgram.Name) : lines.push("")), options.showCurrentProgramTime && "TvChannel" === item.Type && (item.CurrentProgram ? lines.push(getAirTimeText(item.CurrentProgram, !1, !0) || "") : lines.push("")), options.showSeriesTimerTime && (item.RecordAnyTime ? lines.push(globalize.translate("sharedcomponents#Anytime")) : lines.push(datetime.getDisplayTime(item.StartDate))), options.showSeriesTimerChannel && (item.RecordAnyChannel ? lines.push(globalize.translate("sharedcomponents#AllChannels")) : lines.push(item.ChannelName || globalize.translate("sharedcomponents#OneChannel"))), options.showPersonRoleOrType && (item.Role ? lines.push("as " + item.Role) : item.Type ? lines.push(globalize.translate("sharedcomponents#" + item.Type)) : lines.push("")) - }(showTitle || !imgUrl) && forceName && overlayText && 1 === lines.length && (lines = []); - var addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && "none" !== options.cardFooterAside && layoutManager.mobile; - return html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, addRightTextMargin, options.lines), progressHtml && (html += progressHtml), html && (!isOuterFooter || logoUrl || options.cardLayout) && (html = '
' + html, html += "
"), html - } - - function getTextActionButton(item, text, serverId) { - if (text || (text = itemHelper.getDisplayName(item)), layoutManager.tv) return text; - var html = "" - } - - function getItemCountsHtml(options, item) { - var childText, counts = []; - if ("Playlist" === item.Type) { - if (childText = "", item.RunTimeTicks) { - var minutes = item.RunTimeTicks / 6e8; - minutes = minutes || 1, childText += globalize.translate("sharedcomponents#ValueMinutes", Math.round(minutes)) - } else childText += globalize.translate("sharedcomponents#ValueMinutes", 0); - counts.push(childText) - } else "Genre" === item.Type || "Studio" === item.Type ? (item.MovieCount && (childText = 1 === item.MovieCount ? globalize.translate("sharedcomponents#ValueOneMovie") : globalize.translate("sharedcomponents#ValueMovieCount", item.MovieCount), counts.push(childText)), item.SeriesCount && (childText = 1 === item.SeriesCount ? globalize.translate("sharedcomponents#ValueOneSeries") : globalize.translate("sharedcomponents#ValueSeriesCount", item.SeriesCount), counts.push(childText)), item.EpisodeCount && (childText = 1 === item.EpisodeCount ? globalize.translate("sharedcomponents#ValueOneEpisode") : globalize.translate("sharedcomponents#ValueEpisodeCount", item.EpisodeCount), counts.push(childText)), item.GameCount && (childText = 1 === item.GameCount ? globalize.translate("sharedcomponents#ValueOneGame") : globalize.translate("sharedcomponents#ValueGameCount", item.GameCount), counts.push(childText))) : "GameGenre" === item.Type ? item.GameCount && (childText = 1 === item.GameCount ? globalize.translate("sharedcomponents#ValueOneGame") : globalize.translate("sharedcomponents#ValueGameCount", item.GameCount), counts.push(childText)) : "MusicGenre" === item.Type || "MusicArtist" === options.context ? (item.AlbumCount && (childText = 1 === item.AlbumCount ? globalize.translate("sharedcomponents#ValueOneAlbum") : globalize.translate("sharedcomponents#ValueAlbumCount", item.AlbumCount), counts.push(childText)), item.SongCount && (childText = 1 === item.SongCount ? globalize.translate("sharedcomponents#ValueOneSong") : globalize.translate("sharedcomponents#ValueSongCount", item.SongCount), counts.push(childText)), item.MusicVideoCount && (childText = 1 === item.MusicVideoCount ? globalize.translate("sharedcomponents#ValueOneMusicVideo") : globalize.translate("sharedcomponents#ValueMusicVideoCount", item.MusicVideoCount), counts.push(childText))) : "Series" === item.Type && (childText = 1 === item.RecursiveItemCount ? globalize.translate("sharedcomponents#ValueOneEpisode") : globalize.translate("sharedcomponents#ValueEpisodeCount", item.RecursiveItemCount), counts.push(childText)); - return counts.join(", ") - } - - function requireRefreshIndicator() { - refreshIndicatorLoaded || (refreshIndicatorLoaded = !0, require(["emby-itemrefreshindicator"])) - } - - function getDefaultBackgroundClass(str) { - return "defaultCardBackground defaultCardBackground" + getDefaultColorIndex(str) - } - - function buildCard(index, item, apiClient, options) { - var action = options.action || "link"; - "play" === action && item.IsFolder ? action = "link" : "Photo" === item.MediaType && (action = "play"); - var shape = options.shape; - if ("mixed" === shape) { - shape = null; - var primaryImageAspectRatio = item.PrimaryImageAspectRatio; - primaryImageAspectRatio && (shape = primaryImageAspectRatio >= 1.33 ? "mixedBackdrop" : primaryImageAspectRatio > .71 ? "mixedSquare" : "mixedPortrait"), shape = shape || "mixedSquare" - } - var className = "card"; - shape && (className += " " + shape + "Card"), options.cardCssClass && (className += " " + options.cardCssClass), options.cardClass && (className += " " + options.cardClass), layoutManager.desktop && (className += " card-hoverable"), enableFocusTransfrom && layoutManager.tv || (className += " card-nofocustransform"); - var imgInfo = getCardImageUrl(item, apiClient, options, shape), - imgUrl = imgInfo.imgUrl, - forceName = imgInfo.forceName, - showTitle = "auto" === options.showTitle || (options.showTitle || "PhotoAlbum" === item.Type || "Folder" === item.Type), - overlayText = options.overlayText; - forceName && !options.cardLayout && null == overlayText && (overlayText = !0); - var cardImageContainerClass = "cardImageContainer"; - (options.coverImage || imgInfo.coverImage) && (cardImageContainerClass += " coveredImage", ("Photo" === item.MediaType || "PhotoAlbum" === item.Type || "Folder" === item.Type || item.ProgramInfo || "Program" === item.Type || "Recording" === item.Type) && (cardImageContainerClass += " coveredImage-noScale")), imgUrl || (cardImageContainerClass += " " + getDefaultBackgroundClass(item.Name)); - var cardBoxClass = options.cardLayout ? "cardBox visualCardBox" : "cardBox"; - layoutManager.tv && (cardBoxClass += enableFocusTransfrom ? " cardBox-focustransform cardBox-withfocuscontent" : " cardBox-withfocuscontent-large", options.cardLayout && (cardBoxClass += " card-focuscontent", enableFocusTransfrom || (cardBoxClass += " card-focuscontent-large"))); - var footerCssClass, logoUrl, progressHtml = indicators.getProgressBarHtml(item), - innerCardFooter = "", - footerOverlayed = !1; - options.showChannelLogo && item.ChannelPrimaryImageTag ? logoUrl = apiClient.getScaledImageUrl(item.ChannelId, { - type: "Primary", - height: 40, - tag: item.ChannelPrimaryImageTag - }) : options.showLogo && item.ParentLogoImageTag && (logoUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, { - type: "Logo", - height: 40, - tag: item.ParentLogoImageTag - })), overlayText ? (logoUrl = null, footerCssClass = progressHtml ? "innerCardFooter fullInnerCardFooter" : "innerCardFooter", innerCardFooter += getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, !1), footerOverlayed = !0) : progressHtml && (innerCardFooter += '
', innerCardFooter += progressHtml, innerCardFooter += "
", progressHtml = ""); - var mediaSourceCount = item.MediaSourceCount || 1; - mediaSourceCount > 1 && (innerCardFooter += '
' + mediaSourceCount + "
"); - var outerCardFooter = ""; - overlayText || footerOverlayed || (footerCssClass = options.cardLayout ? "cardFooter" : "cardFooter cardFooter-transparent", logoUrl && (footerCssClass += " cardFooter-withlogo"), options.cardLayout || (logoUrl = null), outerCardFooter = getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, !0)), outerCardFooter && !options.cardLayout && (cardBoxClass += " cardBox-bottompadded"); - var overlayButtons = ""; - if (layoutManager.mobile) { - var overlayPlayButton = options.overlayPlayButton; - null != overlayPlayButton || options.overlayMoreButton || options.overlayInfoButton || options.cardLayout || (overlayPlayButton = "Video" === item.MediaType); - var btnCssClass = "cardOverlayButton cardOverlayButton-br itemAction"; - options.centerPlayButton && (overlayButtons += ''), !overlayPlayButton || item.IsPlaceHolder || "Virtual" === item.LocationType && item.MediaType && "Program" !== item.Type || "Person" === item.Type || (overlayButtons += ''), options.overlayMoreButton && (overlayButtons += '') - } - options.showChildCountIndicator && item.ChildCount && (className += " groupedCard"); - var cardImageContainerOpen, cardImageContainerClose = "", - cardBoxClose = "", - cardScalableClose = "", - cardContentClass = "cardContent"; - options.cardLayout || (cardContentClass += " cardContent-shadow"), layoutManager.tv ? (cardImageContainerOpen = imgUrl ? '
' : '
', cardImageContainerClose = "
") : (cardImageContainerOpen = imgUrl ? '"); - var cardScalableClass = "cardScalable"; - layoutManager.tv && !options.cardLayout && (cardScalableClass += " card-focuscontent", enableFocusTransfrom || (cardScalableClass += " card-focuscontent-large")), cardImageContainerOpen = '
' + cardImageContainerOpen, cardBoxClose = "
", cardScalableClose = "
"; - var indicatorsHtml = ""; - if (!1 !== options.missingIndicator && (indicatorsHtml += indicators.getMissingIndicator(item)), indicatorsHtml += indicators.getSyncIndicator(item), indicatorsHtml += indicators.getTimerIndicator(item), indicatorsHtml += indicators.getTypeIndicator(item), options.showGroupCount ? indicatorsHtml += indicators.getChildCountIndicatorHtml(item, { - minCount: 1 - }) : indicatorsHtml += indicators.getPlayedIndicatorHtml(item), "CollectionFolder" === item.Type || item.CollectionType) { - indicatorsHtml += '
', requireRefreshIndicator() - } - indicatorsHtml && (cardImageContainerOpen += '
' + indicatorsHtml + "
"), imgUrl || (cardImageContainerOpen += getCardDefaultText(item, options)); - var tagName = layoutManager.tv && !overlayButtons ? "button" : "div", - nameWithPrefix = item.SortName || item.Name || "", - prefix = nameWithPrefix.substring(0, Math.min(3, nameWithPrefix.length)); - prefix && (prefix = prefix.toUpperCase()); - var timerAttributes = ""; - item.TimerId && (timerAttributes += ' data-timerid="' + item.TimerId + '"'), item.SeriesTimerId && (timerAttributes += ' data-seriestimerid="' + item.SeriesTimerId + '"'); - var actionAttribute; - "button" === tagName ? (className += " itemAction", actionAttribute = ' data-action="' + action + '"') : actionAttribute = "", "MusicAlbum" !== item.Type && "MusicArtist" !== item.Type && "Audio" !== item.Type && (className += " card-withuserdata"); - var positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? ' data-positionticks="' + item.UserData.PlaybackPositionTicks + '"' : "", - collectionIdData = options.collectionId ? ' data-collectionid="' + options.collectionId + '"' : "", - playlistIdData = options.playlistId ? ' data-playlistid="' + options.playlistId + '"' : "", - mediaTypeData = item.MediaType ? ' data-mediatype="' + item.MediaType + '"' : "", - collectionTypeData = item.CollectionType ? ' data-collectiontype="' + item.CollectionType + '"' : "", - channelIdData = item.ChannelId ? ' data-channelid="' + item.ChannelId + '"' : "", - contextData = options.context ? ' data-context="' + options.context + '"' : "", - parentIdData = options.parentId ? ' data-parentid="' + options.parentId + '"' : "", - additionalCardContent = ""; - return layoutManager.desktop && (additionalCardContent += getHoverMenuHtml(item, action)), "<" + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || !1) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + "" - } - - function getHoverMenuHtml(item, action) { - var html = ""; - html += '
'; - var btnCssClass = "cardOverlayButton cardOverlayButton-hover itemAction"; - playbackManager.canPlay(item) && (html += ''), html += '
'; - var userData = item.UserData || {}; - if (itemHelper.canMarkPlayed(item) && (require(["emby-playstatebutton"]), html += ''), itemHelper.canRate(item)) { - var likes = null == userData.Likes ? "" : userData.Likes; - require(["emby-ratingbutton"]), html += '' - } - return html += '', html += "
", html += "
" - } - - function getCardDefaultText(item, options) { - var collectionType = item.CollectionType; - return "livetv" === collectionType ? '' : "homevideos" === collectionType || "photos" === collectionType ? '' : "music" === collectionType ? '' : "MusicAlbum" === item.Type ? '' : "MusicArtist" === item.Type || "Person" === item.Type ? '' : options.defaultCardImageIcon ? '' + options.defaultCardImageIcon + "" : '
' + (isUsingLiveTvNaming(item) ? item.Name : itemHelper.getDisplayName(item)) + "
" - } - - function buildCards(items, options) { - if (document.body.contains(options.itemsContainer)) { - if (options.parentContainer) { - if (!items.length) return void options.parentContainer.classList.add("hide"); - options.parentContainer.classList.remove("hide") - } var html = buildCardsHtmlInternal(items, options); - html ? (options.itemsContainer.cardBuilderHtml !== html && (options.itemsContainer.innerHTML = html, items.length < 50 ? options.itemsContainer.cardBuilderHtml = html : options.itemsContainer.cardBuilderHtml = null), imageLoader.lazyChildren(options.itemsContainer)) : (options.itemsContainer.innerHTML = html, options.itemsContainer.cardBuilderHtml = null), options.autoFocus && focusManager.autoFocus(options.itemsContainer, !0) - } - } - function ensureIndicators(card, indicatorsElem) { - if (indicatorsElem) return indicatorsElem; - if (!(indicatorsElem = card.querySelector(".cardIndicators"))) { - var cardImageContainer = card.querySelector(".cardImageContainer"); - indicatorsElem = document.createElement("div"), - indicatorsElem.classList.add("cardIndicators"), cardImageContainer.appendChild(indicatorsElem) + return html; } - return indicatorsElem - } - function updateUserData(card, userData) { - var type = card.getAttribute("data-type"), - enableCountIndicator = "Series" === type || "BoxSet" === type || "Season" === type, - indicatorsElem = null, - playedIndicator = null, - countIndicator = null, - itemProgressBar = null; - userData.Played ? (playedIndicator = card.querySelector(".playedIndicator"), playedIndicator || (playedIndicator = document.createElement("div"), playedIndicator.classList.add("playedIndicator"), playedIndicator.classList.add("indicator"), indicatorsElem = ensureIndicators(card, indicatorsElem), indicatorsElem.appendChild(playedIndicator)), playedIndicator.innerHTML = '') : (playedIndicator = card.querySelector(".playedIndicator")) && playedIndicator.parentNode.removeChild(playedIndicator), userData.UnplayedItemCount ? (countIndicator = card.querySelector(".countIndicator"), countIndicator || (countIndicator = document.createElement("div"), countIndicator.classList.add("countIndicator"), indicatorsElem = ensureIndicators(card, indicatorsElem), indicatorsElem.appendChild(countIndicator)), countIndicator.innerHTML = userData.UnplayedItemCount) : enableCountIndicator && (countIndicator = card.querySelector(".countIndicator")) && countIndicator.parentNode.removeChild(countIndicator); - var progressHtml = indicators.getProgressBarHtml({ - Type: type, - UserData: userData, - MediaType: "Video" - }); - if (progressHtml) { - if (!(itemProgressBar = card.querySelector(".itemProgressBar"))) { - itemProgressBar = document.createElement("div"), itemProgressBar.classList.add("itemProgressBar"); - var innerCardFooter = card.querySelector(".innerCardFooter"); - if (!innerCardFooter) { - innerCardFooter = document.createElement("div"), innerCardFooter.classList.add("innerCardFooter"); - card.querySelector(".cardImageContainer").appendChild(innerCardFooter) + function getPostersPerRow(shape, screenWidth, isOrientationLandscape) { + + switch (shape) { + + case 'portrait': + if (layoutManager.tv) { + return 100 / 16.66666667; + } + if (screenWidth >= 2200) { + return 100 / 10; + } + if (screenWidth >= 1920) { + return 100 / 11.1111111111; + } + if (screenWidth >= 1600) { + return 100 / 12.5; + } + if (screenWidth >= 1400) { + return 100 / 14.28571428571; + } + if (screenWidth >= 1200) { + return 100 / 16.66666667; + } + if (screenWidth >= 800) { + return 5; + } + if (screenWidth >= 700) { + return 4; + } + if (screenWidth >= 500) { + return 100 / 33.33333333; + } + return 100 / 33.33333333; + case 'square': + if (layoutManager.tv) { + return 100 / 16.66666667; + } + if (screenWidth >= 2200) { + return 100 / 10; + } + if (screenWidth >= 1920) { + return 100 / 11.1111111111; + } + if (screenWidth >= 1600) { + return 100 / 12.5; + } + if (screenWidth >= 1400) { + return 100 / 14.28571428571; + } + if (screenWidth >= 1200) { + return 100 / 16.66666667; + } + if (screenWidth >= 800) { + return 5; + } + if (screenWidth >= 700) { + return 4; + } + if (screenWidth >= 500) { + return 100 / 33.33333333; + } + return 2; + case 'banner': + if (screenWidth >= 2200) { + return 100 / 25; + } + if (screenWidth >= 1200) { + return 100 / 33.33333333; + } + if (screenWidth >= 800) { + return 2; + } + return 1; + case 'backdrop': + if (layoutManager.tv) { + return 100 / 25; + } + if (screenWidth >= 2500) { + return 6; + } + if (screenWidth >= 1600) { + return 5; + } + if (screenWidth >= 1200) { + return 4; + } + if (screenWidth >= 770) { + return 3; + } + if (screenWidth >= 420) { + return 2; + } + return 1; + case 'smallBackdrop': + if (screenWidth >= 1600) { + return 100 / 12.5; + } + if (screenWidth >= 1400) { + return 100 / 14.2857142857; + } + if (screenWidth >= 1200) { + return 100 / 16.666666666666666666; + } + if (screenWidth >= 1000) { + return 5; + } + if (screenWidth >= 800) { + return 4; + } + if (screenWidth >= 500) { + return 100 / 33.33333333; + } + return 2; + case 'overflowSmallBackdrop': + if (layoutManager.tv) { + return 100 / 18.9; + } + if (isOrientationLandscape) { + if (screenWidth >= 800) { + return 100 / 15.5; + } + return 100 / 23.3; + } else { + if (screenWidth >= 540) { + return 100 / 30; + } + return 100 / 72; + } + break; + case 'overflowPortrait': + + if (layoutManager.tv) { + return 100 / 15.5; + } + if (isOrientationLandscape) { + if (screenWidth >= 1700) { + return 100 / 11.6; + } + return 100 / 15.5; + } else { + if (screenWidth >= 1400) { + return 100 / 15; + } + if (screenWidth >= 1200) { + return 100 / 18; + } + if (screenWidth >= 760) { + return 100 / 23; + } + if (screenWidth >= 400) { + return 100 / 31.5; + } + return 100 / 42; + } + break; + case 'overflowSquare': + if (layoutManager.tv) { + return 100 / 15.5; + } + if (isOrientationLandscape) { + if (screenWidth >= 1700) { + return 100 / 11.6; + } + return 100 / 15.5; + } else { + if (screenWidth >= 1400) { + return 100 / 15; + } + if (screenWidth >= 1200) { + return 100 / 18; + } + if (screenWidth >= 760) { + return 100 / 23; + } + if (screenWidth >= 540) { + return 100 / 31.5; + } + return 100 / 42; + } + break; + case 'overflowBackdrop': + if (layoutManager.tv) { + return 100 / 23.3; + } + if (isOrientationLandscape) { + if (screenWidth >= 1700) { + return 100 / 18.5; + } + return 100 / 23.3; + } else { + if (screenWidth >= 1800) { + return 100 / 23.5; + } + if (screenWidth >= 1400) { + return 100 / 30; + } + if (screenWidth >= 760) { + return 100 / 40; + } + if (screenWidth >= 640) { + return 100 / 56; + } + return 100 / 72; + } + break; + default: + return 4; + } + } + + function isResizable(windowWidth) { + + var screen = window.screen; + if (screen) { + var screenWidth = screen.availWidth; + + if ((screenWidth - windowWidth) > 20) { + return true; } - innerCardFooter.appendChild(itemProgressBar) } - itemProgressBar.innerHTML = progressHtml - } else(itemProgressBar = card.querySelector(".itemProgressBar")) && itemProgressBar.parentNode.removeChild(itemProgressBar) - } - function onUserDataChanged(userData, scope) { - for (var cards = (scope || document.body).querySelectorAll('.card-withuserdata[data-id="' + userData.ItemId + '"]'), i = 0, length = cards.length; i < length; i++) updateUserData(cards[i], userData) - } + return false; + } - function onTimerCreated(programId, newTimerId, itemsContainer) { - for (var cells = itemsContainer.querySelectorAll('.card[data-id="' + programId + '"]'), i = 0, length = cells.length; i < length; i++) { - var cell = cells[i]; - if (!cell.querySelector(".timerIndicator")) { - ensureIndicators(cell).insertAdjacentHTML("beforeend", '') + function getImageWidth(shape, screenWidth, isOrientationLandscape) { + + //console.log(screenWidth); + var imagesPerRow = getPostersPerRow(shape, screenWidth, isOrientationLandscape); + //console.log(shape + '--' + imagesPerRow); + + var shapeWidth = screenWidth / imagesPerRow; + + return Math.round(shapeWidth); + } + + function setCardData(items, options) { + + options.shape = options.shape || "auto"; + + var primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items); + + if (options.shape === 'auto' || options.shape === 'autohome' || options.shape === 'autooverflow' || options.shape === 'autoVertical') { + + var requestedShape = options.shape; + options.shape = null; + + if (primaryImageAspectRatio) { + + if (primaryImageAspectRatio >= 3) { + options.shape = 'banner'; + options.coverImage = true; + } else if (primaryImageAspectRatio >= 1.33) { + options.shape = requestedShape === 'autooverflow' ? 'overflowBackdrop' : 'backdrop'; + } else if (primaryImageAspectRatio > 0.71) { + options.shape = requestedShape === 'autooverflow' ? 'overflowSquare' : 'square'; + } else { + options.shape = requestedShape === 'autooverflow' ? 'overflowPortrait' : 'portrait'; + } + } + + if (!options.shape) { + options.shape = options.defaultShape || (requestedShape === 'autooverflow' ? 'overflowSquare' : 'square'); + } } - cell.setAttribute("data-timerid", newTimerId) - } - } - function onTimerCancelled(id, itemsContainer) { - for (var cells = itemsContainer.querySelectorAll('.card[data-timerid="' + id + '"]'), i = 0, length = cells.length; i < length; i++) { - var cell = cells[i], - icon = cell.querySelector(".timerIndicator"); - icon && icon.parentNode.removeChild(icon), cell.removeAttribute("data-timerid") - } - } + if (options.preferThumb === 'auto') { + options.preferThumb = options.shape === 'backdrop' || options.shape === 'overflowBackdrop'; + } - function onSeriesTimerCancelled(id, itemsContainer) { - for (var cells = itemsContainer.querySelectorAll('.card[data-seriestimerid="' + id + '"]'), i = 0, length = cells.length; i < length; i++) { - var cell = cells[i], - icon = cell.querySelector(".timerIndicator"); - icon && icon.parentNode.removeChild(icon), cell.removeAttribute("data-seriestimerid") + options.uiAspect = getDesiredAspect(options.shape); + options.primaryImageAspectRatio = primaryImageAspectRatio; + + if (!options.width && options.widths) { + options.width = options.widths[options.shape]; + } + + if (options.rows && typeof (options.rows) !== 'number') { + options.rows = options.rows[options.shape]; + } + + if (!options.width) { + var screenWidth = dom.getWindowSize().innerWidth; + var screenHeight = dom.getWindowSize().innerHeight; + + if (isResizable(screenWidth)) { + var roundScreenTo = 100; + screenWidth = Math.floor(screenWidth / roundScreenTo) * roundScreenTo; + } + + options.width = getImageWidth(options.shape, screenWidth, screenWidth > (screenHeight * 1.3)); + } } - } - var refreshIndicatorLoaded, enableFocusTransfrom = (window.devicePixelRatio, !browser.slow && !browser.edge), - numRandomColors = 5; - return { - getCardsHtml: getCardsHtml, - buildCards: buildCards, - onUserDataChanged: onUserDataChanged, - onTimerCreated: onTimerCreated, - onTimerCancelled: onTimerCancelled, - onSeriesTimerCancelled: onSeriesTimerCancelled - } -}); \ No newline at end of file + + function buildCardsHtmlInternal(items, options) { + + var isVertical; + + if (options.shape === 'autoVertical') { + isVertical = true; + } + + setCardData(items, options); + + var html = ''; + var itemsInRow = 0; + + var currentIndexValue; + var hasOpenRow; + var hasOpenSection; + + var sectionTitleTagName = options.sectionTitleTagName || 'div'; + var apiClient; + var lastServerId; + + var i, length; + + for (i = 0, length = items.length; i < length; i++) { + + var item = items[i]; + var serverId = item.ServerId || options.serverId; + + if (serverId !== lastServerId) { + lastServerId = serverId; + apiClient = connectionManager.getApiClient(lastServerId); + } + + if (options.indexBy) { + var newIndexValue = ''; + + if (options.indexBy === 'PremiereDate') { + if (item.PremiereDate) { + try { + + newIndexValue = datetime.toLocaleDateString(datetime.parseISO8601Date(item.PremiereDate), { weekday: 'long', month: 'long', day: 'numeric' }); + + } catch (err) { + } + } + } + + else if (options.indexBy === 'ProductionYear') { + newIndexValue = item.ProductionYear; + } + + else if (options.indexBy === 'CommunityRating') { + newIndexValue = item.CommunityRating ? (Math.floor(item.CommunityRating) + (item.CommunityRating % 1 >= 0.5 ? 0.5 : 0)) + '+' : null; + } + + if (newIndexValue !== currentIndexValue) { + + if (hasOpenRow) { + html += '
'; + hasOpenRow = false; + itemsInRow = 0; + } + + if (hasOpenSection) { + + html += ''; + + if (isVertical) { + html += ''; + } + hasOpenSection = false; + } + + if (isVertical) { + html += '
'; + } else { + html += '
'; + } + html += '<' + sectionTitleTagName + ' class="sectionTitle">' + newIndexValue + ''; + if (isVertical) { + html += '
'; + } + currentIndexValue = newIndexValue; + hasOpenSection = true; + } + } + + if (options.rows && itemsInRow === 0) { + + if (hasOpenRow) { + html += '
'; + hasOpenRow = false; + } + + html += '
'; + hasOpenRow = true; + } + + html += buildCard(i, item, apiClient, options); + + itemsInRow++; + + if (options.rows && itemsInRow >= options.rows) { + html += '
'; + hasOpenRow = false; + itemsInRow = 0; + } + } + + if (hasOpenRow) { + html += '
'; + } + + if (hasOpenSection) { + html += '
'; + + if (isVertical) { + html += ''; + } + } + + var cardFooterHtml = ''; + for (i = 0, length = (options.lines || 0); i < length; i++) { + + if (i === 0) { + cardFooterHtml += '
 
'; + } else { + cardFooterHtml += '
 
'; + } + } + + return html; + } + + function getDesiredAspect(shape) { + + if (shape) { + shape = shape.toLowerCase(); + if (shape.indexOf('portrait') !== -1) { + return (2 / 3); + } + if (shape.indexOf('backdrop') !== -1) { + return (16 / 9); + } + if (shape.indexOf('square') !== -1) { + return 1; + } + if (shape.indexOf('banner') !== -1) { + return (1000 / 185); + } + } + return null; + } + + function getCardImageUrl(item, apiClient, options, shape) { + + var imageItem = item.ProgramInfo || item; + item = imageItem; + + var width = options.width; + var height = null; + var primaryImageAspectRatio = item.PrimaryImageAspectRatio; + var forceName = false; + var imgUrl = null; + var coverImage = false; + var uiAspect = null; + + if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxWidth: width, + tag: item.ImageTags.Thumb + }); + + } else if ((options.preferBanner || shape === 'banner') && item.ImageTags && item.ImageTags.Banner) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Banner", + maxWidth: width, + tag: item.ImageTags.Banner + }); + + } else if (options.preferDisc && item.ImageTags && item.ImageTags.Disc) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Disc", + maxWidth: width, + tag: item.ImageTags.Disc + }); + + } else if (options.preferLogo && item.ImageTags && item.ImageTags.Logo) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Logo", + maxWidth: width, + tag: item.ImageTags.Logo + }); + + } else if (options.preferLogo && item.ParentLogoImageTag && item.ParentLogoItemId) { + + imgUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, { + type: "Logo", + maxWidth: width, + tag: item.ParentLogoImageTag + }); + + } else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) { + + imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { + type: "Thumb", + maxWidth: width, + tag: item.SeriesThumbImageTag + }); + + } else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false && item.MediaType !== 'Photo') { + + imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { + type: "Thumb", + maxWidth: width, + tag: item.ParentThumbImageTag + }); + + } else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Backdrop", + maxWidth: width, + tag: item.BackdropImageTags[0] + }); + + forceName = true; + + } else if (options.preferThumb && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false && item.Type === 'Episode') { + + imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { + type: "Backdrop", + maxWidth: width, + tag: item.ParentBackdropImageTags[0] + }); + + } else if (item.ImageTags && item.ImageTags.Primary) { + + height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Primary", + maxHeight: height, + maxWidth: width, + tag: item.ImageTags.Primary + }); + + if (options.preferThumb && options.showTitle !== false) { + forceName = true; + } + + if (primaryImageAspectRatio) { + uiAspect = getDesiredAspect(shape); + if (uiAspect) { + coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2; + } + } + + } else if (item.PrimaryImageTag) { + + height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; + + imgUrl = apiClient.getScaledImageUrl(item.PrimaryImageItemId || item.Id || item.ItemId, { + type: "Primary", + maxHeight: height, + maxWidth: width, + tag: item.PrimaryImageTag + }); + + if (options.preferThumb && options.showTitle !== false) { + forceName = true; + } + + if (primaryImageAspectRatio) { + uiAspect = getDesiredAspect(shape); + if (uiAspect) { + coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2; + } + } + } + else if (item.ParentPrimaryImageTag) { + + imgUrl = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, { + type: "Primary", + maxWidth: width, + tag: item.ParentPrimaryImageTag + }); + } + else if (item.SeriesPrimaryImageTag) { + + imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { + type: "Primary", + maxWidth: width, + tag: item.SeriesPrimaryImageTag + }); + } + else if (item.AlbumId && item.AlbumPrimaryImageTag) { + + width = primaryImageAspectRatio ? Math.round(height * primaryImageAspectRatio) : null; + + imgUrl = apiClient.getScaledImageUrl(item.AlbumId, { + type: "Primary", + maxHeight: height, + maxWidth: width, + tag: item.AlbumPrimaryImageTag + }); + + if (primaryImageAspectRatio) { + uiAspect = getDesiredAspect(shape); + if (uiAspect) { + coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2; + } + } + } + else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxWidth: width, + tag: item.ImageTags.Thumb + }); + + } + else if (item.BackdropImageTags && item.BackdropImageTags.length) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Backdrop", + maxWidth: width, + tag: item.BackdropImageTags[0] + }); + + } else if (item.ImageTags && item.ImageTags.Thumb) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxWidth: width, + tag: item.ImageTags.Thumb + }); + + } else if (item.SeriesThumbImageTag && options.inheritThumb !== false) { + + imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { + type: "Thumb", + maxWidth: width, + tag: item.SeriesThumbImageTag + }); + + } else if (item.ParentThumbItemId && options.inheritThumb !== false) { + + imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { + type: "Thumb", + maxWidth: width, + tag: item.ParentThumbImageTag + }); + + } else if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false) { + + imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { + type: "Backdrop", + maxWidth: width, + tag: item.ParentBackdropImageTags[0] + }); + + } + + return { + imgUrl: imgUrl, + forceName: forceName, + coverImage: coverImage + }; + } + + function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + var numRandomColors = 5; + function getDefaultColorIndex(str) { + + if (str) { + var charIndex = Math.floor(str.length / 2); + var character = String(str.substr(charIndex, 1).charCodeAt()); + var sum = 0; + for (var i = 0; i < character.length; i++) { + sum += parseInt(character.charAt(i)); + } + var index = String(sum).substr(-1); + + return (index % numRandomColors) + 1; + } else { + return getRandomInt(1, numRandomColors); + } + } + + function getCardTextLines(lines, cssClass, forceLines, isOuterFooter, cardLayout, addRightMargin, maxLines) { + + var html = ''; + + var valid = 0; + var i, length; + + for (i = 0, length = lines.length; i < length; i++) { + + var currentCssClass = cssClass; + var text = lines[i]; + + if (valid > 0 && isOuterFooter) { + currentCssClass += ' cardText-secondary'; + } else if (valid === 0 && isOuterFooter) { + currentCssClass += ' cardText-first'; + } + + if (addRightMargin) { + currentCssClass += ' cardText-rightmargin'; + } + + if (text) { + html += "
"; + html += text; + html += "
"; + valid++; + + if (maxLines && valid >= maxLines) { + break; + } + } + } + + if (forceLines) { + + length = maxLines || Math.min(lines.length, maxLines || lines.length); + + while (valid < length) { + html += "
 
"; + valid++; + } + } + + return html; + } + + function isUsingLiveTvNaming(item) { + return item.Type === 'Program' || item.Type === 'Timer' || item.Type === 'Recording'; + } + + function getAirTimeText(item, showAirDateTime, showAirEndTime) { + + var airTimeText = ''; + if (item.StartDate) { + + try { + var date = datetime.parseISO8601Date(item.StartDate); + + if (showAirDateTime) { + airTimeText += datetime.toLocaleDateString(date, { weekday: 'short', month: 'short', day: 'numeric' }) + ' '; + } + + airTimeText += datetime.getDisplayTime(date); + + if (item.EndDate && showAirEndTime) { + date = datetime.parseISO8601Date(item.EndDate); + airTimeText += ' - ' + datetime.getDisplayTime(date); + } + } + catch (e) { + console.log("Error parsing date: " + item.StartDate); + } + } + + return airTimeText; + } + + function getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerClass, progressHtml, logoUrl, isOuterFooter) { + + var html = ''; + + if (logoUrl) { + html += ''; + } + + var showOtherText = isOuterFooter ? !overlayText : overlayText; + + if (isOuterFooter && options.cardLayout && layoutManager.mobile) { + + if (options.cardFooterAside !== 'none') { + html += ''; + } + } + + var cssClass = options.centerText ? "cardText cardTextCentered" : "cardText"; + + var lines = []; + var parentTitleUnderneath = item.Type === 'MusicAlbum' || item.Type === 'Audio' || item.Type === 'MusicVideo'; + var titleAdded; + + if (showOtherText) { + if ((options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) { + + if (isOuterFooter && item.Type === 'Episode' && item.SeriesName) { + + if (item.SeriesId) { + lines.push(getTextActionButton({ + Id: item.SeriesId, + ServerId: item.ServerId, + Name: item.SeriesName, + Type: 'Series', + IsFolder: true + })); + } else { + lines.push(item.SeriesName); + } + } + else { + + if (isUsingLiveTvNaming(item)) { + + lines.push(item.Name); + + if (!item.EpisodeTitle) { + titleAdded = true; + } + + } else { + var parentTitle = item.SeriesName || item.Series || item.Album || item.AlbumArtist || item.GameSystem || ""; + + if (parentTitle || showTitle) { + lines.push(parentTitle); + } + } + } + } + } + + var showMediaTitle = (showTitle && !titleAdded) || (options.showParentTitleOrTitle && !lines.length); + if (!showMediaTitle && !titleAdded && (showTitle || forceName)) { + showMediaTitle = true; + } + + if (showMediaTitle) { + + var name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item, { + includeParentInfo: options.includeParentInfoInTitle + }); + + lines.push(name); + } + + if (showOtherText) { + if (options.showParentTitle && parentTitleUnderneath) { + + if (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) { + item.AlbumArtists[0].Type = 'MusicArtist'; + item.AlbumArtists[0].IsFolder = true; + lines.push(getTextActionButton(item.AlbumArtists[0], null, item.ServerId)); + } else { + lines.push(isUsingLiveTvNaming(item) ? item.Name : (item.SeriesName || item.Series || item.Album || item.AlbumArtist || item.GameSystem || "")); + } + } + + if (options.showItemCounts) { + + var itemCountHtml = getItemCountsHtml(options, item); + + lines.push(itemCountHtml); + } + + if (options.textLines) { + var additionalLines = options.textLines(item); + for (var i = 0, length = additionalLines.length; i < length; i++) { + lines.push(additionalLines[i]); + } + } + + if (options.showSongCount) { + + var songLine = ''; + + if (item.SongCount) { + songLine = item.SongCount === 1 ? + globalize.translate('sharedcomponents#ValueOneSong') : + globalize.translate('sharedcomponents#ValueSongCount', item.SongCount); + } + + lines.push(songLine); + } + + if (options.showPremiereDate) { + + if (item.PremiereDate) { + try { + + lines.push(getPremiereDateText(item)); + + } catch (err) { + lines.push(''); + + } + } else { + lines.push(''); + } + } + + if (options.showYear || options.showSeriesYear) { + + if (item.Type === 'Series') { + if (item.Status === "Continuing") { + + lines.push(globalize.translate('sharedcomponents#SeriesYearToPresent', item.ProductionYear || '')); + + } else { + + if (item.EndDate && item.ProductionYear) { + lines.push(item.ProductionYear + ' - ' + datetime.parseISO8601Date(item.EndDate).getFullYear()); + } else { + lines.push(item.ProductionYear || ''); + } + } + } else { + lines.push(item.ProductionYear || ''); + } + } + + if (options.showRuntime) { + + if (item.RunTimeTicks) { + + lines.push(datetime.getDisplayRunningTime(item.RunTimeTicks)); + } else { + lines.push(''); + } + } + + if (options.showAirTime) { + + lines.push(getAirTimeText(item, options.showAirDateTime, options.showAirEndTime) || ''); + } + + if (options.showChannelName) { + + if (item.ChannelId) { + + lines.push(getTextActionButton({ + + Id: item.ChannelId, + ServerId: item.ServerId, + Name: item.ChannelName, + Type: 'TvChannel', + MediaType: item.MediaType, + IsFolder: false + + }, item.ChannelName)); + } else { + lines.push(item.ChannelName || ' '); + } + } + + if (options.showCurrentProgram && item.Type === 'TvChannel') { + + if (item.CurrentProgram) { + lines.push(item.CurrentProgram.Name); + } else { + lines.push(''); + } + } + + if (options.showCurrentProgramTime && item.Type === 'TvChannel') { + + if (item.CurrentProgram) { + lines.push(getAirTimeText(item.CurrentProgram, false, true) || ''); + } else { + lines.push(''); + } + } + + if (options.showSeriesTimerTime) { + if (item.RecordAnyTime) { + + lines.push(globalize.translate('sharedcomponents#Anytime')); + } else { + lines.push(datetime.getDisplayTime(item.StartDate)); + } + } + + if (options.showSeriesTimerChannel) { + if (item.RecordAnyChannel) { + lines.push(globalize.translate('sharedcomponents#AllChannels')); + } + else { + lines.push(item.ChannelName || globalize.translate('sharedcomponents#OneChannel')); + } + } + + if (options.showPersonRoleOrType) { + if (item.Role) { + lines.push('as ' + item.Role); + } + else if (item.Type) { + lines.push(globalize.translate('sharedcomponents#' + item.Type)); + } else { + lines.push(''); + } + } + } + + if ((showTitle || !imgUrl) && forceName && overlayText && lines.length === 1) { + lines = []; + } + + var addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile; + + html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, addRightTextMargin, options.lines); + + if (progressHtml) { + html += progressHtml; + } + + if (html) { + + if (!isOuterFooter || logoUrl || options.cardLayout) { + html = '
' + html; + + //cardFooter + html += "
"; + } + } + + return html; + } + + function getTextActionButton(item, text, serverId) { + + if (!text) { + text = itemHelper.getDisplayName(item); + } + + if (layoutManager.tv) { + return text; + } + + var html = ''; + + return html; + } + + function getItemCountsHtml(options, item) { + + var counts = []; + + var childText; + + if (item.Type === 'Playlist') { + + childText = ''; + + if (item.RunTimeTicks) { + + var minutes = item.RunTimeTicks / 600000000; + + minutes = minutes || 1; + + childText += globalize.translate('sharedcomponents#ValueMinutes', Math.round(minutes)); + + } else { + childText += globalize.translate('sharedcomponents#ValueMinutes', 0); + } + + counts.push(childText); + + } + else if (item.Type === 'Genre' || item.Type === 'Studio') { + + if (item.MovieCount) { + + childText = item.MovieCount === 1 ? + globalize.translate('sharedcomponents#ValueOneMovie') : + globalize.translate('sharedcomponents#ValueMovieCount', item.MovieCount); + + counts.push(childText); + } + + if (item.SeriesCount) { + + childText = item.SeriesCount === 1 ? + globalize.translate('sharedcomponents#ValueOneSeries') : + globalize.translate('sharedcomponents#ValueSeriesCount', item.SeriesCount); + + counts.push(childText); + } + if (item.EpisodeCount) { + + childText = item.EpisodeCount === 1 ? + globalize.translate('sharedcomponents#ValueOneEpisode') : + globalize.translate('sharedcomponents#ValueEpisodeCount', item.EpisodeCount); + + counts.push(childText); + } + if (item.GameCount) { + + childText = item.GameCount === 1 ? + globalize.translate('sharedcomponents#ValueOneGame') : + globalize.translate('sharedcomponents#ValueGameCount', item.GameCount); + + counts.push(childText); + } + + } else if (item.Type === 'GameGenre') { + + if (item.GameCount) { + + childText = item.GameCount === 1 ? + globalize.translate('sharedcomponents#ValueOneGame') : + globalize.translate('sharedcomponents#ValueGameCount', item.GameCount); + + counts.push(childText); + } + } else if (item.Type === 'MusicGenre' || options.context === "MusicArtist") { + + if (item.AlbumCount) { + + childText = item.AlbumCount === 1 ? + globalize.translate('sharedcomponents#ValueOneAlbum') : + globalize.translate('sharedcomponents#ValueAlbumCount', item.AlbumCount); + + counts.push(childText); + } + if (item.SongCount) { + + childText = item.SongCount === 1 ? + globalize.translate('sharedcomponents#ValueOneSong') : + globalize.translate('sharedcomponents#ValueSongCount', item.SongCount); + + counts.push(childText); + } + if (item.MusicVideoCount) { + + childText = item.MusicVideoCount === 1 ? + globalize.translate('sharedcomponents#ValueOneMusicVideo') : + globalize.translate('sharedcomponents#ValueMusicVideoCount', item.MusicVideoCount); + + counts.push(childText); + } + + } else if (item.Type === 'Series') { + + childText = item.RecursiveItemCount === 1 ? + globalize.translate('sharedcomponents#ValueOneEpisode') : + globalize.translate('sharedcomponents#ValueEpisodeCount', item.RecursiveItemCount); + + counts.push(childText); + } + + return counts.join(', '); + } + + function getProgramIndicators(item) { + + item = item.ProgramInfo || item; + + var html = ''; + + if (item.IsLive) { + html += '
' + globalize.translate('sharedcomponents#Live') + '
'; + } + + if (item.IsPremiere) { + html += '
' + globalize.translate('sharedcomponents#Premiere') + '
'; + } + else if (item.IsSeries && !item.IsRepeat) { + html += '
' + globalize.translate('sharedcomponents#AttributeNew') + '
'; + } + //else if (item.IsRepeat) { + // html += '
' + globalize.translate('sharedcomponents#Repeat') + '
'; + //} + + if (html) { + html = '
' + html; + html += '
'; + } + + return html; + } + + var refreshIndicatorLoaded; + function requireRefreshIndicator() { + + if (!refreshIndicatorLoaded) { + refreshIndicatorLoaded = true; + require(['emby-itemrefreshindicator']); + } + } + + function getDefaultBackgroundClass(str) { + return 'defaultCardBackground defaultCardBackground' + getDefaultColorIndex(str); + } + + function buildCard(index, item, apiClient, options) { + + var action = options.action || 'link'; + + if (action === 'play' && item.IsFolder) { + // If this hard-coding is ever removed make sure to test nested photo albums + action = 'link'; + } + else if (item.MediaType === 'Photo') { + action = 'play'; + } + + var shape = options.shape; + + if (shape === 'mixed') { + + shape = null; + + var primaryImageAspectRatio = item.PrimaryImageAspectRatio; + + if (primaryImageAspectRatio) { + + if (primaryImageAspectRatio >= 1.33) { + shape = 'mixedBackdrop'; + } else if (primaryImageAspectRatio > 0.71) { + shape = 'mixedSquare'; + } else { + shape = 'mixedPortrait'; + } + } + + shape = shape || 'mixedSquare'; + } + + var className = 'card'; + + if (shape) { + className += ' ' + shape + 'Card'; + } + + if (options.cardCssClass) { + className += ' ' + options.cardCssClass; + } + + if (options.cardClass) { + className += " " + options.cardClass; + } + + if (layoutManager.desktop) { + className += ' card-hoverable'; + } + + if (!enableFocusTransfrom || !layoutManager.tv) { + className += ' card-nofocustransform'; + } + + var imgInfo = getCardImageUrl(item, apiClient, options, shape); + var imgUrl = imgInfo.imgUrl; + + var forceName = imgInfo.forceName; + + var showTitle = options.showTitle === 'auto' ? true : (options.showTitle || item.Type === 'PhotoAlbum' || item.Type === 'Folder'); + var overlayText = options.overlayText; + + if (forceName && !options.cardLayout) { + + if (overlayText == null) { + overlayText = true; + } + } + + var cardImageContainerClass = 'cardImageContainer'; + var coveredImage = options.coverImage || imgInfo.coverImage; + + if (coveredImage) { + cardImageContainerClass += ' coveredImage'; + + if (item.MediaType === 'Photo' || item.Type === 'PhotoAlbum' || item.Type === 'Folder' || item.ProgramInfo || item.Type === 'Program' || item.Type === 'Recording') { + cardImageContainerClass += ' coveredImage-noScale'; + } + } + + if (!imgUrl) { + cardImageContainerClass += ' ' + getDefaultBackgroundClass(item.Name); + } + + var cardBoxClass = options.cardLayout ? 'cardBox visualCardBox' : 'cardBox'; + + if (layoutManager.tv) { + + if (enableFocusTransfrom) { + cardBoxClass += ' cardBox-focustransform cardBox-withfocuscontent'; + } else { + cardBoxClass += ' cardBox-withfocuscontent-large'; + } + + if (options.cardLayout) { + cardBoxClass += ' card-focuscontent'; + + if (!enableFocusTransfrom) { + cardBoxClass += ' card-focuscontent-large'; + } + } + } + + var footerCssClass; + var progressHtml = indicators.getProgressBarHtml(item); + + var innerCardFooter = ''; + + var footerOverlayed = false; + + var logoUrl; + var logoHeight = 40; + + if (options.showChannelLogo && item.ChannelPrimaryImageTag) { + logoUrl = apiClient.getScaledImageUrl(item.ChannelId, { + type: "Primary", + height: logoHeight, + tag: item.ChannelPrimaryImageTag + }); + } + else if (options.showLogo && item.ParentLogoImageTag) { + logoUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, { + type: "Logo", + height: logoHeight, + tag: item.ParentLogoImageTag + }); + } + + if (overlayText) { + + logoUrl = null; + + footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter'; + innerCardFooter += getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, false); + footerOverlayed = true; + } + else if (progressHtml) { + innerCardFooter += '
'; + innerCardFooter += progressHtml; + innerCardFooter += '
'; + + progressHtml = ''; + } + + var mediaSourceCount = item.MediaSourceCount || 1; + if (mediaSourceCount > 1) { + innerCardFooter += '
' + mediaSourceCount + '
'; + } + + var outerCardFooter = ''; + if (!overlayText && !footerOverlayed) { + footerCssClass = options.cardLayout ? 'cardFooter' : 'cardFooter cardFooter-transparent'; + + if (logoUrl) { + footerCssClass += ' cardFooter-withlogo'; + } + + if (!options.cardLayout) { + logoUrl = null; + } + + outerCardFooter = getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, true); + } + + if (outerCardFooter && !options.cardLayout /*&& options.allowBottomPadding !== false*/) { + cardBoxClass += ' cardBox-bottompadded'; + } + + var overlayButtons = ''; + if (layoutManager.mobile) { + + var overlayPlayButton = options.overlayPlayButton; + + if (overlayPlayButton == null && !options.overlayMoreButton && !options.overlayInfoButton && !options.cardLayout) { + overlayPlayButton = item.MediaType === 'Video'; + } + + var btnCssClass = 'cardOverlayButton cardOverlayButton-br itemAction'; + + if (options.centerPlayButton) { + overlayButtons += ''; + } + + if (overlayPlayButton && !item.IsPlaceHolder && (item.LocationType !== 'Virtual' || !item.MediaType || item.Type === 'Program') && item.Type !== 'Person') { + overlayButtons += ''; + } + + if (options.overlayMoreButton) { + + overlayButtons += ''; + } + } + + if (options.showChildCountIndicator && item.ChildCount) { + className += ' groupedCard'; + } + + // cardBox can be it's own separate element if an outer footer is ever needed + var cardImageContainerOpen; + var cardImageContainerClose = ''; + var cardBoxClose = ''; + var cardScalableClose = ''; + + var cardContentClass = 'cardContent'; + if (!options.cardLayout) { + cardContentClass += ' cardContent-shadow'; + } + + if (layoutManager.tv) { + + // Don't use the IMG tag with safari because it puts a white border around it + cardImageContainerOpen = imgUrl ? ('
') : ('
'); + + cardImageContainerClose = '
'; + } else { + // Don't use the IMG tag with safari because it puts a white border around it + cardImageContainerOpen = imgUrl ? (''; + } + + var cardScalableClass = 'cardScalable'; + + if (layoutManager.tv && !options.cardLayout) { + + cardScalableClass += ' card-focuscontent'; + + if (!enableFocusTransfrom) { + cardScalableClass += ' card-focuscontent-large'; + } + } + + cardImageContainerOpen = '
' + cardImageContainerOpen; + cardBoxClose = '
'; + cardScalableClose = '
'; + + var indicatorsHtml = ''; + + if (options.missingIndicator !== false) { + indicatorsHtml += indicators.getMissingIndicator(item); + } + + indicatorsHtml += indicators.getSyncIndicator(item); + indicatorsHtml += indicators.getTimerIndicator(item); + + indicatorsHtml += indicators.getTypeIndicator(item); + + if (options.showGroupCount) { + + indicatorsHtml += indicators.getChildCountIndicatorHtml(item, { + minCount: 1 + }); + } + else { + indicatorsHtml += indicators.getPlayedIndicatorHtml(item); + } + + if (item.Type === 'CollectionFolder' || item.CollectionType) { + var refreshClass = item.RefreshProgress || (item.RefreshStatus && virtualFolder.item !== 'Idle') ? '' : ' class="hide"'; + indicatorsHtml += '
'; + requireRefreshIndicator(); + } + + if (indicatorsHtml) { + cardImageContainerOpen += '
' + indicatorsHtml + '
'; + } + + //if (item.Type === 'Program' || item.Type === 'Timer') { + // cardImageContainerOpen += getProgramIndicators(item); + //} + + if (!imgUrl) { + cardImageContainerOpen += getCardDefaultText(item, options); + } + + var tagName = (layoutManager.tv) && !overlayButtons ? 'button' : 'div'; + + var nameWithPrefix = (item.SortName || item.Name || ''); + var prefix = nameWithPrefix.substring(0, Math.min(3, nameWithPrefix.length)); + + if (prefix) { + prefix = prefix.toUpperCase(); + } + + var timerAttributes = ''; + if (item.TimerId) { + timerAttributes += ' data-timerid="' + item.TimerId + '"'; + } + if (item.SeriesTimerId) { + timerAttributes += ' data-seriestimerid="' + item.SeriesTimerId + '"'; + } + + var actionAttribute; + + if (tagName === 'button') { + className += " itemAction"; + actionAttribute = ' data-action="' + action + '"'; + } else { + actionAttribute = ''; + } + + if (item.Type !== 'MusicAlbum' && item.Type !== 'MusicArtist' && item.Type !== 'Audio') { + className += ' card-withuserdata'; + } + + var positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? (' data-positionticks="' + item.UserData.PlaybackPositionTicks + '"') : ''; + var collectionIdData = options.collectionId ? (' data-collectionid="' + options.collectionId + '"') : ''; + var playlistIdData = options.playlistId ? (' data-playlistid="' + options.playlistId + '"') : ''; + var mediaTypeData = item.MediaType ? (' data-mediatype="' + item.MediaType + '"') : ''; + var collectionTypeData = item.CollectionType ? (' data-collectiontype="' + item.CollectionType + '"') : ''; + var channelIdData = item.ChannelId ? (' data-channelid="' + item.ChannelId + '"') : ''; + var contextData = options.context ? (' data-context="' + options.context + '"') : ''; + var parentIdData = options.parentId ? (' data-parentid="' + options.parentId + '"') : ''; + + var additionalCardContent = ''; + + if (layoutManager.desktop) { + additionalCardContent += getHoverMenuHtml(item, action); + } + + return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + ''; + } + + function getHoverMenuHtml(item, action) { + + var html = ''; + + html += '
'; + + var btnCssClass = 'cardOverlayButton cardOverlayButton-hover itemAction'; + + if (playbackManager.canPlay(item)) { + + html += ''; + } + + html += '
'; + + //if (itemHelper.canEdit({ Policy: { IsAdministrator: true } }, item)) { + + // //require(['emby-playstatebutton']); + // html += ''; + //} + + var userData = item.UserData || {}; + + if (itemHelper.canMarkPlayed(item)) { + + require(['emby-playstatebutton']); + html += ''; + } + + if (itemHelper.canRate(item)) { + + var likes = userData.Likes == null ? '' : userData.Likes; + + require(['emby-ratingbutton']); + html += ''; + } + + html += ''; + + html += '
'; + html += '
'; + + return html; + } + + function getCardDefaultText(item, options) { + + var collectionType = item.CollectionType; + if (collectionType === 'livetv') { + return ''; + } + if (collectionType === 'homevideos' || collectionType === 'photos') { + return ''; + } + if (collectionType === 'music') { + return ''; + } + if (item.Type === 'MusicAlbum') { + return ''; + } + if (item.Type === 'MusicArtist' || item.Type === 'Person') { + return ''; + } + if (options.defaultCardImageIcon) { + return '' + options.defaultCardImageIcon + ''; + } + + var defaultName = isUsingLiveTvNaming(item) ? item.Name : itemHelper.getDisplayName(item); + return '
' + defaultName + '
'; + } + + function buildCards(items, options) { + + // Abort if the container has been disposed + if (!document.body.contains(options.itemsContainer)) { + return; + } + + if (options.parentContainer) { + if (items.length) { + options.parentContainer.classList.remove('hide'); + } else { + options.parentContainer.classList.add('hide'); + return; + } + } + + var html = buildCardsHtmlInternal(items, options); + + if (html) { + + if (options.itemsContainer.cardBuilderHtml !== html) { + options.itemsContainer.innerHTML = html; + + if (items.length < 50) { + options.itemsContainer.cardBuilderHtml = html; + } else { + options.itemsContainer.cardBuilderHtml = null; + } + } + + imageLoader.lazyChildren(options.itemsContainer); + } else { + + options.itemsContainer.innerHTML = html; + options.itemsContainer.cardBuilderHtml = null; + } + + if (options.autoFocus) { + focusManager.autoFocus(options.itemsContainer, true); + } + } + + function ensureIndicators(card, indicatorsElem) { + + if (indicatorsElem) { + return indicatorsElem; + } + + indicatorsElem = card.querySelector('.cardIndicators'); + + if (!indicatorsElem) { + + var cardImageContainer = card.querySelector('.cardImageContainer'); + indicatorsElem = document.createElement('div'); + indicatorsElem.classList.add('cardIndicators'); + cardImageContainer.appendChild(indicatorsElem); + } + + return indicatorsElem; + } + + function updateUserData(card, userData) { + + var type = card.getAttribute('data-type'); + var enableCountIndicator = type === 'Series' || type === 'BoxSet' || type === 'Season'; + var indicatorsElem = null; + var playedIndicator = null; + var countIndicator = null; + var itemProgressBar = null; + + if (userData.Played) { + + playedIndicator = card.querySelector('.playedIndicator'); + + if (!playedIndicator) { + + playedIndicator = document.createElement('div'); + playedIndicator.classList.add('playedIndicator'); + playedIndicator.classList.add('indicator'); + indicatorsElem = ensureIndicators(card, indicatorsElem); + indicatorsElem.appendChild(playedIndicator); + } + playedIndicator.innerHTML = ''; + } else { + + playedIndicator = card.querySelector('.playedIndicator'); + if (playedIndicator) { + + playedIndicator.parentNode.removeChild(playedIndicator); + } + } + if (userData.UnplayedItemCount) { + countIndicator = card.querySelector('.countIndicator'); + + if (!countIndicator) { + + countIndicator = document.createElement('div'); + countIndicator.classList.add('countIndicator'); + indicatorsElem = ensureIndicators(card, indicatorsElem); + indicatorsElem.appendChild(countIndicator); + } + countIndicator.innerHTML = userData.UnplayedItemCount; + } else if (enableCountIndicator) { + + countIndicator = card.querySelector('.countIndicator'); + if (countIndicator) { + + countIndicator.parentNode.removeChild(countIndicator); + } + } + + var progressHtml = indicators.getProgressBarHtml({ + Type: type, + UserData: userData, + MediaType: 'Video' + }); + + if (progressHtml) { + + itemProgressBar = card.querySelector('.itemProgressBar'); + + if (!itemProgressBar) { + itemProgressBar = document.createElement('div'); + itemProgressBar.classList.add('itemProgressBar'); + + var innerCardFooter = card.querySelector('.innerCardFooter'); + if (!innerCardFooter) { + innerCardFooter = document.createElement('div'); + innerCardFooter.classList.add('innerCardFooter'); + var cardImageContainer = card.querySelector('.cardImageContainer'); + cardImageContainer.appendChild(innerCardFooter); + } + innerCardFooter.appendChild(itemProgressBar); + } + + itemProgressBar.innerHTML = progressHtml; + } + else { + + itemProgressBar = card.querySelector('.itemProgressBar'); + if (itemProgressBar) { + itemProgressBar.parentNode.removeChild(itemProgressBar); + } + } + } + + function onUserDataChanged(userData, scope) { + + var cards = (scope || document.body).querySelectorAll('.card-withuserdata[data-id="' + userData.ItemId + '"]'); + + for (var i = 0, length = cards.length; i < length; i++) { + updateUserData(cards[i], userData); + } + } + + function onTimerCreated(programId, newTimerId, itemsContainer) { + + var cells = itemsContainer.querySelectorAll('.card[data-id="' + programId + '"]'); + + for (var i = 0, length = cells.length; i < length; i++) { + var cell = cells[i]; + var icon = cell.querySelector('.timerIndicator'); + if (!icon) { + var indicatorsElem = ensureIndicators(cell); + indicatorsElem.insertAdjacentHTML('beforeend', ''); + } + cell.setAttribute('data-timerid', newTimerId); + } + } + + function onTimerCancelled(id, itemsContainer) { + + var cells = itemsContainer.querySelectorAll('.card[data-timerid="' + id + '"]'); + + for (var i = 0, length = cells.length; i < length; i++) { + var cell = cells[i]; + var icon = cell.querySelector('.timerIndicator'); + if (icon) { + icon.parentNode.removeChild(icon); + } + cell.removeAttribute('data-timerid'); + } + } + + function onSeriesTimerCancelled(id, itemsContainer) { + + var cells = itemsContainer.querySelectorAll('.card[data-seriestimerid="' + id + '"]'); + + for (var i = 0, length = cells.length; i < length; i++) { + var cell = cells[i]; + var icon = cell.querySelector('.timerIndicator'); + if (icon) { + icon.parentNode.removeChild(icon); + } + cell.removeAttribute('data-seriestimerid'); + } + } + + return { + getCardsHtml: getCardsHtml, + buildCards: buildCards, + onUserDataChanged: onUserDataChanged, + onTimerCreated: onTimerCreated, + onTimerCancelled: onTimerCancelled, + onSeriesTimerCancelled: onSeriesTimerCancelled + }; + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/cardbuilder/chaptercardbuilder.js b/src/bower_components/emby-webcomponents/cardbuilder/chaptercardbuilder.js index 55ff68eb5a..900f4befc1 100644 --- a/src/bower_components/emby-webcomponents/cardbuilder/chaptercardbuilder.js +++ b/src/bower_components/emby-webcomponents/cardbuilder/chaptercardbuilder.js @@ -1,59 +1,140 @@ -define(["datetime", "imageLoader", "connectionManager", "layoutManager", "browser"], function(datetime, imageLoader, connectionManager, layoutManager, browser) { - "use strict"; +define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browser'], function (datetime, imageLoader, connectionManager, layoutManager, browser) { + 'use strict'; function buildChapterCardsHtml(item, chapters, options) { - var className = "card itemAction chapterCard"; - layoutManager.tv && (browser.animate || browser.edge) && (className += " card-focusscale"); - var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [], - videoStream = mediaStreams.filter(function(i) { - return "Video" === i.Type - })[0] || {}, - shape = options.backdropShape || "backdrop"; - videoStream.Width && videoStream.Height && videoStream.Width / videoStream.Height <= 1.2 && (shape = options.squareShape || "square"), className += " " + shape + "Card", (options.block || options.rows) && (className += " block"); - for (var html = "", itemsInRow = 0, apiClient = connectionManager.getApiClient(item.ServerId), i = 0, length = chapters.length; i < length; i++) { - options.rows && 0 === itemsInRow && (html += '
'); - html += buildChapterCard(item, apiClient, chapters[i], i, options, className, shape), itemsInRow++, options.rows && itemsInRow >= options.rows && (itemsInRow = 0, html += "
") + + var className = 'card itemAction chapterCard'; + + if (layoutManager.tv && (browser.animate || browser.edge)) { + className += ' card-focusscale'; } - return html + + var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || []; + var videoStream = mediaStreams.filter(function (i) { + return i.Type === 'Video'; + })[0] || {}; + + var shape = (options.backdropShape || 'backdrop'); + + if (videoStream.Width && videoStream.Height) { + + if ((videoStream.Width / videoStream.Height) <= 1.2) { + shape = (options.squareShape || 'square'); + } + } + + className += ' ' + shape + 'Card'; + + if (options.block || options.rows) { + className += ' block'; + } + + var html = ''; + var itemsInRow = 0; + + var apiClient = connectionManager.getApiClient(item.ServerId); + + for (var i = 0, length = chapters.length; i < length; i++) { + + if (options.rows && itemsInRow === 0) { + html += '
'; + } + + var chapter = chapters[i]; + + html += buildChapterCard(item, apiClient, chapter, i, options, className, shape); + itemsInRow++; + + if (options.rows && itemsInRow >= options.rows) { + itemsInRow = 0; + html += '
'; + } + } + + return html; } function getImgUrl(item, chapter, index, maxWidth, apiClient) { - return chapter.ImageTag ? apiClient.getScaledImageUrl(item.Id, { - maxWidth: maxWidth, - tag: chapter.ImageTag, - type: "Chapter", - index: index - }) : null + + if (chapter.ImageTag) { + + return apiClient.getScaledImageUrl(item.Id, { + + maxWidth: maxWidth, + tag: chapter.ImageTag, + type: "Chapter", + index: index + }); + } + + return null; } function buildChapterCard(item, apiClient, chapter, index, options, className, shape) { - var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient), - cardImageContainerClass = "cardContent cardContent-shadow cardImageContainer chapterCardImageContainer"; - options.coverImage && (cardImageContainerClass += " coveredImage"); - var dataAttributes = ' data-action="play" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-positionticks="' + chapter.StartPositionTicks + '"', - cardImageContainer = imgUrl ? '
' : '
'; - imgUrl || (cardImageContainer += 'local_movies'); - var nameHtml = ""; - nameHtml += '
' + chapter.Name + "
", nameHtml += '
' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + "
"; - var cardBoxCssClass = "cardBox", - cardScalableClass = "cardScalable"; + + var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient); + + var cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer'; + if (options.coverImage) { + cardImageContainerClass += ' coveredImage'; + } + var dataAttributes = ' data-action="play" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-positionticks="' + chapter.StartPositionTicks + '"'; + var cardImageContainer = imgUrl ? ('
') : ('
'); + + if (!imgUrl) { + cardImageContainer += 'local_movies'; + } + + var nameHtml = ''; + nameHtml += '
' + chapter.Name + '
'; + nameHtml += '
' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + '
'; + + var cardBoxCssClass = 'cardBox'; + var cardScalableClass = 'cardScalable'; + if (layoutManager.tv) { var enableFocusTransfrom = !browser.slow && !browser.edge; - cardScalableClass += " card-focuscontent", enableFocusTransfrom ? cardBoxCssClass += " cardBox-focustransform cardBox-withfocuscontent" : (cardBoxCssClass += " cardBox-withfocuscontent-large", cardScalableClass += " card-focuscontent-large") + + cardScalableClass += ' card-focuscontent'; + + if (enableFocusTransfrom) { + cardBoxCssClass += ' cardBox-focustransform cardBox-withfocuscontent'; + } else { + cardBoxCssClass += ' cardBox-withfocuscontent-large'; + cardScalableClass += ' card-focuscontent-large'; + } } - return '
" + + var html = '
'; + + return html; } function buildChapterCards(item, chapters, options) { + if (options.parentContainer) { - if (!document.body.contains(options.parentContainer)) return; - if (!chapters.length) return void options.parentContainer.classList.add("hide"); - options.parentContainer.classList.remove("hide") + // Abort if the container has been disposed + if (!document.body.contains(options.parentContainer)) { + return; + } + + if (chapters.length) { + options.parentContainer.classList.remove('hide'); + } else { + options.parentContainer.classList.add('hide'); + return; + } } + var html = buildChapterCardsHtml(item, chapters, options); - options.itemsContainer.innerHTML = html, imageLoader.lazyChildren(options.itemsContainer) + + options.itemsContainer.innerHTML = html; + + imageLoader.lazyChildren(options.itemsContainer); } + return { buildChapterCards: buildChapterCards - } + }; + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/cardbuilder/peoplecardbuilder.js b/src/bower_components/emby-webcomponents/cardbuilder/peoplecardbuilder.js index 4dc70f7ed4..e0a5050dc5 100644 --- a/src/bower_components/emby-webcomponents/cardbuilder/peoplecardbuilder.js +++ b/src/bower_components/emby-webcomponents/cardbuilder/peoplecardbuilder.js @@ -1,18 +1,22 @@ -define(["cardBuilder"], function(cardBuilder) { - "use strict"; +define(['cardBuilder'], function (cardBuilder) { + 'use strict'; function buildPeopleCards(items, options) { + options = Object.assign(options || {}, { - cardLayout: !1, - centerText: !0, - showTitle: !0, - cardFooterAside: "none", - showPersonRoleOrType: !0, - cardCssClass: "personCard", - defaultCardImageIcon: "" - }), cardBuilder.buildCards(items, options) + cardLayout: false, + centerText: true, + showTitle: true, + cardFooterAside: 'none', + showPersonRoleOrType: true, + cardCssClass: 'personCard', + defaultCardImageIcon: '' + }); + cardBuilder.buildCards(items, options); } + return { buildPeopleCards: buildPeopleCards - } + }; + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/cardbuilder/roundcard.css b/src/bower_components/emby-webcomponents/cardbuilder/roundcard.css index dec5e8d58f..d0bd950972 100644 --- a/src/bower_components/emby-webcomponents/cardbuilder/roundcard.css +++ b/src/bower_components/emby-webcomponents/cardbuilder/roundcard.css @@ -1,10 +1,7 @@ -.card-round:focus>.cardBox-focustransform { - -webkit-transform: scale(1.26, 1.26); - transform: scale(1.26, 1.26) +.card-round:focus > .cardBox-focustransform { + transform: scale(1.26, 1.26); } -.cardImage-round, -.cardImageContainer-round { - -webkit-border-radius: 1000px; - border-radius: 1000px -} \ No newline at end of file +.cardImageContainer-round, .cardImage-round { + border-radius: 1000px; +} diff --git a/src/bower_components/emby-webcomponents/chromecast/chromecasthelpers.js b/src/bower_components/emby-webcomponents/chromecast/chromecasthelpers.js index e3330bf37e..4950f6540e 100644 --- a/src/bower_components/emby-webcomponents/chromecast/chromecasthelpers.js +++ b/src/bower_components/emby-webcomponents/chromecast/chromecasthelpers.js @@ -1,67 +1,228 @@ -define(["events"], function(events) { - "use strict"; +define(['events'], function (events) { + 'use strict'; + + // LinkParser + // + // https://github.com/ravisorg/LinkParser + // + // Locate and extract almost any URL within a string. Handles protocol-less domains, IPv4 and + // IPv6, unrecognised TLDs, and more. + // + // This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. + // http://creativecommons.org/licenses/by-sa/4.0/ + (function () { + + // Original URL regex from the Android android.text.util.Linkify function, found here: + // http://stackoverflow.com/a/19696443 + // + // However there were problems with it, most probably related to the fact it was + // written in 2007, and it's been highly modified. + // + // 1) I didn't like the fact that it was tied to specific TLDs, since new ones + // are being added all the time it wouldn't be reasonable to expect developer to + // be continually updating their regular expressions. + // + // 2) It didn't allow unicode characters in the domains which are now allowed in + // many languages, (including some IDN TLDs). Again these are constantly being + // added to and it doesn't seem reasonable to hard-code them. Note this ended up + // not being possible in standard JS due to the way it handles multibyte strings. + // It is possible using XRegExp, however a big performance hit results. Disabled + // for now. + // + // 3) It didn't allow for IPv6 hostnames + // IPv6 regex from http://stackoverflow.com/a/17871737 + // + // 4) It was very poorly commented + // + // 5) It wasn't as smart as it could have been about what should be part of a + // URL and what should be part of human language. + + var protocols = "(?:(?:http|https|rtsp|ftp):\\/\\/)"; + var credentials = "(?:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,64}" // username (1-64 normal or url escaped characters) + + "(?:\\:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,25})?" // followed by optional password (: + 1-25 normal or url escaped characters) + + "\\@)"; + + // IPv6 Regex http://forums.intermapper.com/viewtopic.php?t=452 + // by Dartware, LLC is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License + // http://intermapper.com/ + var ipv6 = "(" + + "(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))" + + "|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))" + + "|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))" + + "|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))" + + "|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))" + + "|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))" + + "|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))" + + "|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))" + + ")(%.+)?"; + + var ipv4 = "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\." + + "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\." + + "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\." + + "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])"; + + // This would have been a lot cleaner if JS RegExp supported conditionals... + var linkRegExpString = + + // begin match for protocol / username / password / host + "(?:" + + // ============================ + // If we have a recognized protocol at the beginning of the URL, we're + // more relaxed about what we accept, because we assume the user wants + // this to be a URL, and we're not accidentally matching human language + + protocols + "?" + + // optional username:password@ + + credentials + "?" + + // IP address (both v4 and v6) + + "(?:" + + // IPv6 + + ipv6 + + // IPv4 + + "|" + ipv4 + + + ")" + + // end match for protocol / username / password / host + + ")" + + // optional port number + + "(?:\\:\\d{1,5})?" + + // plus optional path and query params (no unicode allowed here?) + + "(?:" + + "\\/(?:" + // some characters we'll accept because it's unlikely human language + // would use them after a URL unless they were part of the url + + "(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])" + + "|(?:\\%[a-f0-9]{2})" + // some characters are much more likely to be used AFTER a url and + // were not intended to be included in the url itself. Mostly end + // of sentence type things. It's also likely that the URL would + // still work if any of these characters were missing from the end + // because we parsed it incorrectly. For these characters to be accepted + // they must be followed by another character that we're reasonably + // sure is part of the url + + "|(?:[\\;\\?\\:\\.\\!\\'\\(\\)\\,\\=]+(?=(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2})))" + + ")*" + + "|\\b|\$" + + ")"; + + // regex = XRegExp(regex,'gi'); + var linkRegExp = RegExp(linkRegExpString, 'gi'); + + var protocolRegExp = RegExp('^' + protocols, 'i'); + + // if url doesn't begin with a known protocol, add http by default + function ensureProtocol(url) { + if (!url.match(protocolRegExp)) { + url = "http://" + url; + } + return url; + } + + // look for links in the text + var LinkParser = { + parse: function (text) { + var links = []; + var match; + + while (match = linkRegExp.exec(text)) { + // console.log(matches); + var txt = match[0]; + var pos = match.index; + var len = txt.length; + var url = ensureProtocol(text); + links.push({ 'pos': pos, 'text': txt, 'len': len, 'url': url }); + } + + return links; + } + + }; + + window.LinkParser = LinkParser; + })(); + + var cache = {}; function isValidIpAddress(address) { - return 1 == LinkParser.parse(address).length + + var links = LinkParser.parse(address); + + return links.length == 1; } function isLocalIpAddress(address) { - return address = address.toLowerCase(), -1 !== address.indexOf("127.0.0.1") || -1 !== address.indexOf("localhost") + + address = address.toLowerCase(); + + if (address.indexOf('127.0.0.1') !== -1) { + return true; + } + if (address.indexOf('localhost') !== -1) { + return true; + } + + return false; } function getServerAddress(apiClient) { + var serverAddress = apiClient.serverAddress(); - if (isValidIpAddress(serverAddress) && !isLocalIpAddress(serverAddress)) return Promise.resolve(serverAddress); + + if (isValidIpAddress(serverAddress) && !isLocalIpAddress(serverAddress)) { + return Promise.resolve(serverAddress); + } + var cachedValue = getCachedValue(serverAddress); - return cachedValue ? Promise.resolve(cachedValue) : apiClient.getEndpointInfo().then(function(endpoint) { - return endpoint.IsInNetwork ? apiClient.getPublicSystemInfo().then(function(info) { - return addToCache(serverAddress, info.LocalAddress), info.LocalAddress - }) : (addToCache(serverAddress, serverAddress), serverAddress) - }) + if (cachedValue) { + return Promise.resolve(cachedValue); + } + + return apiClient.getEndpointInfo().then(function (endpoint) { + if (endpoint.IsInNetwork) { + return apiClient.getPublicSystemInfo().then(function (info) { + addToCache(serverAddress, info.LocalAddress); + return info.LocalAddress; + }); + } else { + addToCache(serverAddress, serverAddress); + return serverAddress; + } + }); } function clearCache() { - cache = {} + cache = {}; } function addToCache(key, value) { cache[key] = { value: value, - time: (new Date).getTime() - } + time: new Date().getTime() + }; } function getCachedValue(key) { + var obj = cache[key]; - return obj && (new Date).getTime() - obj.time < 18e4 ? obj.value : null - }! function() { - function ensureProtocol(url) { - return url.match(protocolRegExp) || (url = "http://" + url), url + + if (obj && (new Date().getTime() - obj.time) < 180000) { + return obj.value; } - var protocols = "(?:(?:http|https|rtsp|ftp):\\/\\/)", - linkRegExp = RegExp("(?:(?:(?:http|https|rtsp|ftp):\\/\\/)?(?:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,64}(?:\\:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,25})?\\@)?(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?|(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\\:\\d{1,5})?(?:\\/(?:(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2})|(?:[\\;\\?\\:\\.\\!\\'\\(\\)\\,\\=]+(?=(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2}))))*|\\b|$)", "gi"), - protocolRegExp = RegExp("^" + protocols, "i"), - LinkParser = { - parse: function(text) { - for (var match, links = []; match = linkRegExp.exec(text);) { - var txt = match[0], - pos = match.index, - len = txt.length, - url = ensureProtocol(text); - links.push({ - pos: pos, - text: txt, - len: len, - url: url - }) - } - return links - } - }; - window.LinkParser = LinkParser - }(); - var cache = {}; - return events.on(ConnectionManager, "localusersignedin", clearCache), events.on(ConnectionManager, "localusersignedout", clearCache), { - getServerAddress: getServerAddress + + return null; } + + events.on(ConnectionManager, 'localusersignedin', clearCache); + events.on(ConnectionManager, 'localusersignedout', clearCache); + + return { + getServerAddress: getServerAddress + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/chromecast/chromecastplayer.js b/src/bower_components/emby-webcomponents/chromecast/chromecastplayer.js index 08b28d1aec..2ee47924dd 100644 --- a/src/bower_components/emby-webcomponents/chromecast/chromecastplayer.js +++ b/src/bower_components/emby-webcomponents/chromecast/chromecastplayer.js @@ -1,139 +1,329 @@ -define(["appSettings", "userSettings", "playbackManager", "connectionManager", "globalize", "events", "require", "castSenderApiLoader"], function(appSettings, userSettings, playbackManager, connectionManager, globalize, events, require, castSenderApiLoader) { - "use strict"; +define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', 'globalize', 'events', 'require', 'castSenderApiLoader'], function (appSettings, userSettings, playbackManager, connectionManager, globalize, events, require, castSenderApiLoader) { + 'use strict'; + + // Based on https://github.com/googlecast/CastVideos-chrome/blob/master/CastVideos.js + var currentResolve; + var currentReject; + + var PlayerName = 'Chromecast'; function sendConnectionResult(isOk) { - var resolve = currentResolve, - reject = currentReject; - currentResolve = null, currentReject = null, isOk ? resolve && resolve() : reject ? reject() : playbackManager.removeActivePlayer(PlayerName) + + var resolve = currentResolve; + var reject = currentReject; + + currentResolve = null; + currentReject = null; + + if (isOk) { + if (resolve) { + resolve(); + } + } else { + if (reject) { + reject(); + } else { + playbackManager.removeActivePlayer(PlayerName); + } + } } + /** + * Constants of states for Chromecast device + **/ + var DEVICE_STATE = { + 'IDLE': 0, + 'ACTIVE': 1, + 'WARNING': 2, + 'ERROR': 3 + }; + + /** + * Constants of states for CastPlayer + **/ + var PLAYER_STATE = { + 'IDLE': 'IDLE', + 'LOADING': 'LOADING', + 'LOADED': 'LOADED', + 'PLAYING': 'PLAYING', + 'PAUSED': 'PAUSED', + 'STOPPED': 'STOPPED', + 'SEEKING': 'SEEKING', + 'ERROR': 'ERROR' + }; + + var applicationID = "2D4B1DA3"; + + // This is the beta version used for testing new changes + + //applicationID = '27C4EB5B'; + + var messageNamespace = 'urn:x-cast:com.connectsdk'; + + var CastPlayer = function () { + + /* device variables */ + // @type {DEVICE_STATE} A state for device + this.deviceState = DEVICE_STATE.IDLE; + + /* Cast player variables */ + // @type {Object} a chrome.cast.media.Media object + this.currentMediaSession = null; + + // @type {string} a chrome.cast.Session object + this.session = null; + // @type {PLAYER_STATE} A state for Cast media player + this.castPlayerState = PLAYER_STATE.IDLE; + + this.hasReceivers = false; + + // bind once - commit 2ebffc2271da0bc5e8b13821586aee2a2e3c7753 + this.errorHandler = this.onError.bind(this); + this.mediaStatusUpdateHandler = this.onMediaStatusUpdate.bind(this); + + this.initializeCastPlayer(); + }; + + /** + * Initialize Cast media player + * Initializes the API. Note that either successCallback and errorCallback will be + * invoked once the API has finished initialization. The sessionListener and + * receiverListener may be invoked at any time afterwards, and possibly more than once. + */ + CastPlayer.prototype.initializeCastPlayer = function () { + + var chrome = window.chrome; + + if (!chrome) { + return; + } + + if (!chrome.cast || !chrome.cast.isAvailable) { + + setTimeout(this.initializeCastPlayer.bind(this), 1000); + return; + } + + // request session + var sessionRequest = new chrome.cast.SessionRequest(applicationID); + var apiConfig = new chrome.cast.ApiConfig(sessionRequest, + this.sessionListener.bind(this), + this.receiverListener.bind(this), + "origin_scoped"); + + console.log('chromecast.initialize'); + + chrome.cast.initialize(apiConfig, this.onInitSuccess.bind(this), this.errorHandler); + + }; + + /** + * Callback function for init success + */ + CastPlayer.prototype.onInitSuccess = function () { + this.isInitialized = true; + console.log("chromecast init success"); + }; + + /** + * Generic error callback function + */ + CastPlayer.prototype.onError = function () { + console.log("chromecast error"); + }; + + /** + * @param {!Object} e A new session + * This handles auto-join when a page is reloaded + * When active session is detected, playback will automatically + * join existing session and occur in Cast mode and media + * status gets synced up with current media of the session + */ + CastPlayer.prototype.sessionListener = function (e) { + + this.session = e; + if (this.session) { + + //console.log('sessionListener ' + JSON.stringify(e)); + + if (this.session.media[0]) { + this.onMediaDiscovered('activeSession', this.session.media[0]); + } + + this.onSessionConnected(e); + } + }; + function alertText(text, title) { - require(["alert"], function(alert) { + require(['alert'], function (alert) { alert({ text: text, title: title - }) - }) + }); + }); } - function normalizeImages(state) { - if (state && state.NowPlayingItem) { - var item = state.NowPlayingItem; - item.ImageTags && item.ImageTags.Primary || item.PrimaryImageTag && (item.ImageTags = item.ImageTags || {}, item.ImageTags.Primary = item.PrimaryImageTag), item.BackdropImageTag && item.BackdropItemId === item.Id && (item.BackdropImageTags = [item.BackdropImageTag]), item.BackdropImageTag && item.BackdropItemId !== item.Id && (item.ParentBackdropImageTags = [item.BackdropImageTag], item.ParentBackdropItemId = item.BackdropItemId) + CastPlayer.prototype.messageListener = function (namespace, message) { + + if (typeof (message) === 'string') { + message = JSON.parse(message); } - } - function getItemsForPlayback(apiClient, query) { - var userId = apiClient.getCurrentUserId(); - return query.Ids && 1 === query.Ids.split(",").length ? apiClient.getItem(userId, query.Ids.split(",")).then(function(item) { - return { - Items: [item], - TotalRecordCount: 1 - } - }) : (query.Limit = query.Limit || 100, query.ExcludeLocationTypes = "Virtual", query.EnableTotalRecordCount = !1, apiClient.getItems(userId, query)) - } + if (message.type === 'playbackerror') { - function bindEventForRelay(instance, eventName) { - events.on(instance._castPlayer, eventName, function(e, data) { - var state = instance.getPlayerStateInternal(data); - events.trigger(instance, eventName, [state]) - }) - } - - function initializeChromecast() { - var instance = this; - instance._castPlayer = new CastPlayer, document.dispatchEvent(new CustomEvent("chromecastloaded", { - detail: { - player: instance - } - })), events.on(instance._castPlayer, "connect", function(e) { - currentResolve ? sendConnectionResult(!0) : playbackManager.setActivePlayer(PlayerName, instance.getCurrentTargetInfo()), console.log("cc: connect"), instance.lastPlayerData = null - }), events.on(instance._castPlayer, "playbackstart", function(e, data) { - console.log("cc: playbackstart"), instance._castPlayer.initializeCastPlayer(); - var state = instance.getPlayerStateInternal(data); - events.trigger(instance, "playbackstart", [state]) - }), events.on(instance._castPlayer, "playbackstop", function(e, data) { - console.log("cc: playbackstop"); - var state = instance.getPlayerStateInternal(data); - events.trigger(instance, "playbackstop", [state]), instance.lastPlayerData = {} - }), events.on(instance._castPlayer, "playbackprogress", function(e, data) { - var state = instance.getPlayerStateInternal(data); - events.trigger(instance, "timeupdate", [state]) - }), bindEventForRelay(instance, "timeupdate"), bindEventForRelay(instance, "pause"), bindEventForRelay(instance, "unpause"), bindEventForRelay(instance, "volumechange"), bindEventForRelay(instance, "repeatmodechange"), events.on(instance._castPlayer, "playstatechange", function(e, data) { - var state = instance.getPlayerStateInternal(data); - events.trigger(instance, "pause", [state]) - }) - } - - function ChromecastPlayer() { - this.name = PlayerName, this.type = "mediaplayer", this.id = "chromecast", this.isLocalPlayer = !1, this.lastPlayerData = {}, castSenderApiLoader.load().then(initializeChromecast.bind(this)) - } - var currentResolve, currentReject, PlayerName = "Chromecast", - DEVICE_STATE = { - IDLE: 0, - ACTIVE: 1, - WARNING: 2, - ERROR: 3 - }, - PLAYER_STATE = { - IDLE: "IDLE", - LOADING: "LOADING", - LOADED: "LOADED", - PLAYING: "PLAYING", - PAUSED: "PAUSED", - STOPPED: "STOPPED", - SEEKING: "SEEKING", - ERROR: "ERROR" - }, - CastPlayer = function() { - this.deviceState = DEVICE_STATE.IDLE, this.currentMediaSession = null, this.session = null, this.castPlayerState = PLAYER_STATE.IDLE, this.hasReceivers = !1, this.errorHandler = this.onError.bind(this), this.mediaStatusUpdateHandler = this.onMediaStatusUpdate.bind(this), this.initializeCastPlayer() - }; - return CastPlayer.prototype.initializeCastPlayer = function() { - var chrome = window.chrome; - if (chrome) { - if (!chrome.cast || !chrome.cast.isAvailable) return void setTimeout(this.initializeCastPlayer.bind(this), 1e3); - var sessionRequest = new chrome.cast.SessionRequest("2D4B1DA3"), - apiConfig = new chrome.cast.ApiConfig(sessionRequest, this.sessionListener.bind(this), this.receiverListener.bind(this), "origin_scoped"); - console.log("chromecast.initialize"), chrome.cast.initialize(apiConfig, this.onInitSuccess.bind(this), this.errorHandler) - } - }, CastPlayer.prototype.onInitSuccess = function() { - this.isInitialized = !0, console.log("chromecast init success") - }, CastPlayer.prototype.onError = function() { - console.log("chromecast error") - }, CastPlayer.prototype.sessionListener = function(e) { - this.session = e, this.session && (this.session.media[0] && this.onMediaDiscovered("activeSession", this.session.media[0]), this.onSessionConnected(e)) - }, CastPlayer.prototype.messageListener = function(namespace, message) { - if ("string" == typeof message && (message = JSON.parse(message)), "playbackerror" === message.type) { var errorCode = message.data; - setTimeout(function() { - alertText(globalize.translate("MessagePlaybackError" + errorCode), globalize.translate("HeaderPlaybackError")) - }, 300) - } else "connectionerror" === message.type ? setTimeout(function() { - alertText(globalize.translate("MessageChromecastConnectionError"), globalize.translate("HeaderError")) - }, 300) : message.type && events.trigger(this, message.type, [message.data]) - }, CastPlayer.prototype.receiverListener = function(e) { - this.hasReceivers = "available" === e - }, CastPlayer.prototype.sessionUpdateListener = function(isAlive) { - isAlive || (this.session = null, this.deviceState = DEVICE_STATE.IDLE, this.castPlayerState = PLAYER_STATE.IDLE, this.currentMediaSession = null, sendConnectionResult(!1)) - }, CastPlayer.prototype.launchApp = function() { - chrome.cast.requestSession(this.onRequestSessionSuccess.bind(this), this.onLaunchError.bind(this)) - }, CastPlayer.prototype.onRequestSessionSuccess = function(e) { - this.onSessionConnected(e) - }, CastPlayer.prototype.onSessionConnected = function(session) { - this.session = session, this.deviceState = DEVICE_STATE.ACTIVE, this.session.addMessageListener("urn:x-cast:com.connectsdk", this.messageListener.bind(this)), this.session.addMediaListener(this.sessionMediaListener.bind(this)), this.session.addUpdateListener(this.sessionUpdateListener.bind(this)), events.trigger(this, "connect"), this.sendMessage({ + + setTimeout(function () { + alertText(globalize.translate('MessagePlaybackError' + errorCode), globalize.translate('HeaderPlaybackError')); + }, 300); + + } + else if (message.type === 'connectionerror') { + + setTimeout(function () { + alertText(globalize.translate('MessageChromecastConnectionError'), globalize.translate('HeaderError')); + }, 300); + + } + else if (message.type) { + events.trigger(this, message.type, [message.data]); + } + }; + + /** + * @param {string} e Receiver availability + * This indicates availability of receivers but + * does not provide a list of device IDs + */ + CastPlayer.prototype.receiverListener = function (e) { + + if (e === 'available') { + //console.log("chromecast receiver found"); + this.hasReceivers = true; + } + else { + //console.log("chromecast receiver list empty"); + this.hasReceivers = false; + } + }; + + /** + * session update listener + */ + CastPlayer.prototype.sessionUpdateListener = function (isAlive) { + + //console.log('sessionUpdateListener alive: ' + isAlive); + + if (isAlive) { + } + else { + this.session = null; + this.deviceState = DEVICE_STATE.IDLE; + this.castPlayerState = PLAYER_STATE.IDLE; + + //console.log('sessionUpdateListener: setting currentMediaSession to null'); + this.currentMediaSession = null; + + sendConnectionResult(false); + } + }; + + /** + * Requests that a receiver application session be created or joined. By default, the SessionRequest + * passed to the API at initialization time is used; this may be overridden by passing a different + * session request in opt_sessionRequest. + */ + CastPlayer.prototype.launchApp = function () { + //console.log("chromecast launching app..."); + chrome.cast.requestSession(this.onRequestSessionSuccess.bind(this), this.onLaunchError.bind(this)); + }; + + /** + * Callback function for request session success + * @param {Object} e A chrome.cast.Session object + */ + CastPlayer.prototype.onRequestSessionSuccess = function (e) { + + //console.log("chromecast session success: " + e.sessionId); + this.onSessionConnected(e); + }; + + CastPlayer.prototype.onSessionConnected = function (session) { + + this.session = session; + + this.deviceState = DEVICE_STATE.ACTIVE; + + this.session.addMessageListener(messageNamespace, this.messageListener.bind(this)); + this.session.addMediaListener(this.sessionMediaListener.bind(this)); + this.session.addUpdateListener(this.sessionUpdateListener.bind(this)); + + events.trigger(this, 'connect'); + + this.sendMessage({ options: {}, - command: "Identify" - }) - }, CastPlayer.prototype.sessionMediaListener = function(e) { - this.currentMediaSession = e, this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler) - }, CastPlayer.prototype.onLaunchError = function() { - this.deviceState = DEVICE_STATE.ERROR, sendConnectionResult(!1) - }, CastPlayer.prototype.stopApp = function() { - this.session && this.session.stop(this.onStopAppSuccess.bind(this, "Session stopped"), this.errorHandler) - }, CastPlayer.prototype.onStopAppSuccess = function(message) { - this.deviceState = DEVICE_STATE.IDLE, this.castPlayerState = PLAYER_STATE.IDLE, this.currentMediaSession = null - }, CastPlayer.prototype.loadMedia = function(options, command) { - return this.session ? (options.items = options.items.map(function(i) { + command: 'Identify' + }); + }; + + /** + * session update listener + */ + CastPlayer.prototype.sessionMediaListener = function (e) { + + //console.log('sessionMediaListener'); + this.currentMediaSession = e; + this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler); + }; + + /** + * Callback function for launch error + */ + CastPlayer.prototype.onLaunchError = function () { + //console.log("chromecast launch error"); + this.deviceState = DEVICE_STATE.ERROR; + + sendConnectionResult(false); + }; + + /** + * Stops the running receiver application associated with the session. + */ + CastPlayer.prototype.stopApp = function () { + + if (this.session) { + this.session.stop(this.onStopAppSuccess.bind(this, 'Session stopped'), + this.errorHandler); + } + + }; + + /** + * Callback function for stop app success + */ + CastPlayer.prototype.onStopAppSuccess = function (message) { + //console.log(message); + this.deviceState = DEVICE_STATE.IDLE; + this.castPlayerState = PLAYER_STATE.IDLE; + + //console.log('onStopAppSuccess: setting currentMediaSession to null'); + this.currentMediaSession = null; + }; + + /** + * Loads media into a running receiver application + * @param {Number} mediaIndex An index number to indicate current media content + */ + CastPlayer.prototype.loadMedia = function (options, command) { + + if (!this.session) { + //console.log("no session"); + return Promise.reject(); + } + + // Convert the items to smaller stubs to send the minimal amount of information + options.items = options.items.map(function (i) { + return { Id: i.Id, ServerId: i.ServerId, @@ -141,18 +331,37 @@ define(["appSettings", "userSettings", "playbackManager", "connectionManager", " Type: i.Type, MediaType: i.MediaType, IsFolder: i.IsFolder - } - }), this.sendMessage({ + }; + }); + + return this.sendMessage({ options: options, command: command - })) : Promise.reject() - }, CastPlayer.prototype.sendMessage = function(message) { - var player = this, - receiverName = null, - session = player.session; - session && session.receiver && session.receiver.friendlyName && (receiverName = session.receiver.friendlyName); + }); + }; + + CastPlayer.prototype.sendMessage = function (message) { + + var player = this; + + var receiverName = null; + + var session = player.session; + + if (session && session.receiver && session.receiver.friendlyName) { + receiverName = session.receiver.friendlyName; + } + var apiClient; - apiClient = message.options && message.options.ServerId ? connectionManager.getApiClient(message.options.ServerId) : message.options && message.options.items && message.options.items.length ? connectionManager.getApiClient(message.options.items[0].ServerId) : connectionManager.currentApiClient(), message = Object.assign(message, { + if (message.options && message.options.ServerId) { + apiClient = connectionManager.getApiClient(message.options.ServerId); + } else if (message.options && message.options.items && message.options.items.length) { + apiClient = connectionManager.getApiClient(message.options.items[0].ServerId); + } else { + apiClient = connectionManager.currentApiClient(); + } + + message = Object.assign(message, { userId: apiClient.getCurrentUserId(), deviceId: apiClient.deviceId(), accessToken: apiClient.accessToken(), @@ -161,265 +370,755 @@ define(["appSettings", "userSettings", "playbackManager", "connectionManager", " serverVersion: apiClient.serverVersion(), receiverName: receiverName }); + var bitrateSetting = appSettings.maxChromecastBitrate(); - return bitrateSetting && (message.maxBitrate = bitrateSetting), message.options && message.options.items && (message.subtitleAppearance = userSettings.getSubtitleAppearanceSettings(), message.subtitleBurnIn = appSettings.get("subtitleburnin") || ""), new Promise(function(resolve, reject) { - require(["chromecastHelper"], function(chromecastHelper) { - chromecastHelper.getServerAddress(apiClient).then(function(serverAddress) { - message.serverAddress = serverAddress, player.sendMessageInternal(message).then(resolve, reject) - }, reject) - }) - }) - }, CastPlayer.prototype.sendMessageInternal = function(message) { - return message = JSON.stringify(message), this.session.sendMessage("urn:x-cast:com.connectsdk", message, this.onPlayCommandSuccess.bind(this), this.errorHandler), Promise.resolve() - }, CastPlayer.prototype.onPlayCommandSuccess = function() {}, CastPlayer.prototype.onMediaDiscovered = function(how, mediaSession) { - this.currentMediaSession = mediaSession, "loadMedia" === how && (this.castPlayerState = PLAYER_STATE.PLAYING), "activeSession" === how && (this.castPlayerState = mediaSession.playerState), this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler) - }, CastPlayer.prototype.onMediaStatusUpdate = function(e) { - !1 === e && (this.castPlayerState = PLAYER_STATE.IDLE) - }, CastPlayer.prototype.setReceiverVolume = function(mute, vol) { - this.currentMediaSession && (mute ? this.session.setReceiverMuted(!0, this.mediaCommandSuccessCallback.bind(this), this.errorHandler) : this.session.setReceiverVolumeLevel(vol || 1, this.mediaCommandSuccessCallback.bind(this), this.errorHandler)) - }, CastPlayer.prototype.mute = function() { - this.setReceiverVolume(!0) - }, CastPlayer.prototype.mediaCommandSuccessCallback = function(info, e) {}, ChromecastPlayer.prototype.tryPair = function(target) { + if (bitrateSetting) { + message.maxBitrate = bitrateSetting; + } + + if (message.options && message.options.items) { + message.subtitleAppearance = userSettings.getSubtitleAppearanceSettings(); + message.subtitleBurnIn = appSettings.get('subtitleburnin') || ''; + } + + return new Promise(function (resolve, reject) { + + require(['chromecastHelper'], function (chromecastHelper) { + + chromecastHelper.getServerAddress(apiClient).then(function (serverAddress) { + message.serverAddress = serverAddress; + player.sendMessageInternal(message).then(resolve, reject); + + }, reject); + }); + }); + }; + + CastPlayer.prototype.sendMessageInternal = function (message) { + + message = JSON.stringify(message); + //console.log(message); + + this.session.sendMessage(messageNamespace, message, this.onPlayCommandSuccess.bind(this), this.errorHandler); + return Promise.resolve(); + }; + + CastPlayer.prototype.onPlayCommandSuccess = function () { + //console.log('Message was sent to receiver ok.'); + }; + + /** + * Callback function for loadMedia success + * @param {Object} mediaSession A new media object. + */ + CastPlayer.prototype.onMediaDiscovered = function (how, mediaSession) { + + //console.log("chromecast new media session ID:" + mediaSession.mediaSessionId + ' (' + how + ')'); + this.currentMediaSession = mediaSession; + + if (how === 'loadMedia') { + this.castPlayerState = PLAYER_STATE.PLAYING; + } + + if (how === 'activeSession') { + this.castPlayerState = mediaSession.playerState; + } + + this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler); + }; + + /** + * Callback function for media status update from receiver + * @param {!Boolean} e true/false + */ + CastPlayer.prototype.onMediaStatusUpdate = function (e) { + + if (e === false) { + this.castPlayerState = PLAYER_STATE.IDLE; + } + //console.log("chromecast updating media: " + e); + }; + + /** + * Set media volume in Cast mode + * @param {Boolean} mute A boolean + */ + CastPlayer.prototype.setReceiverVolume = function (mute, vol) { + + if (!this.currentMediaSession) { + //console.log('this.currentMediaSession is null'); + return; + } + + if (!mute) { + + this.session.setReceiverVolumeLevel((vol || 1), + this.mediaCommandSuccessCallback.bind(this), + this.errorHandler); + } + else { + this.session.setReceiverMuted(true, + this.mediaCommandSuccessCallback.bind(this), + this.errorHandler); + } + }; + + /** + * Mute CC + */ + CastPlayer.prototype.mute = function () { + this.setReceiverVolume(true); + }; + + /** + * Callback function for media command success + */ + CastPlayer.prototype.mediaCommandSuccessCallback = function (info, e) { + //console.log(info); + }; + + function normalizeImages(state) { + + if (state && state.NowPlayingItem) { + + var item = state.NowPlayingItem; + + if (!item.ImageTags || !item.ImageTags.Primary) { + if (item.PrimaryImageTag) { + item.ImageTags = item.ImageTags || {}; + item.ImageTags.Primary = item.PrimaryImageTag; + } + } + if (item.BackdropImageTag && item.BackdropItemId === item.Id) { + item.BackdropImageTags = [item.BackdropImageTag]; + } + if (item.BackdropImageTag && item.BackdropItemId !== item.Id) { + item.ParentBackdropImageTags = [item.BackdropImageTag]; + item.ParentBackdropItemId = item.BackdropItemId; + } + } + } + + function getItemsForPlayback(apiClient, query) { + + var userId = apiClient.getCurrentUserId(); + + if (query.Ids && query.Ids.split(',').length === 1) { + return apiClient.getItem(userId, query.Ids.split(',')).then(function (item) { + return { + Items: [item], + TotalRecordCount: 1 + }; + }); + } + else { + + query.Limit = query.Limit || 100; + query.ExcludeLocationTypes = "Virtual"; + query.EnableTotalRecordCount = false; + + return apiClient.getItems(userId, query); + } + } + + function bindEventForRelay(instance, eventName) { + + events.on(instance._castPlayer, eventName, function (e, data) { + + //console.log('cc: ' + eventName); + var state = instance.getPlayerStateInternal(data); + + events.trigger(instance, eventName, [state]); + }); + } + + function initializeChromecast() { + + var instance = this; + instance._castPlayer = new CastPlayer(); + + // To allow the native android app to override + document.dispatchEvent(new CustomEvent("chromecastloaded", { + detail: { + player: instance + } + })); + + events.on(instance._castPlayer, "connect", function (e) { + + if (currentResolve) { + sendConnectionResult(true); + } else { + playbackManager.setActivePlayer(PlayerName, instance.getCurrentTargetInfo()); + } + + console.log('cc: connect'); + // Reset this so that statechange will fire + instance.lastPlayerData = null; + }); + + events.on(instance._castPlayer, "playbackstart", function (e, data) { + + console.log('cc: playbackstart'); + + instance._castPlayer.initializeCastPlayer(); + + var state = instance.getPlayerStateInternal(data); + events.trigger(instance, "playbackstart", [state]); + }); + + events.on(instance._castPlayer, "playbackstop", function (e, data) { + + console.log('cc: playbackstop'); + var state = instance.getPlayerStateInternal(data); + + events.trigger(instance, "playbackstop", [state]); + + // Reset this so the next query doesn't make it appear like content is playing. + instance.lastPlayerData = {}; + }); + + events.on(instance._castPlayer, "playbackprogress", function (e, data) { + + //console.log('cc: positionchange'); + var state = instance.getPlayerStateInternal(data); + + events.trigger(instance, "timeupdate", [state]); + }); + + bindEventForRelay(instance, 'timeupdate'); + bindEventForRelay(instance, 'pause'); + bindEventForRelay(instance, 'unpause'); + bindEventForRelay(instance, 'volumechange'); + bindEventForRelay(instance, 'repeatmodechange'); + + events.on(instance._castPlayer, "playstatechange", function (e, data) { + + //console.log('cc: playstatechange'); + var state = instance.getPlayerStateInternal(data); + + events.trigger(instance, "pause", [state]); + }); + } + + function ChromecastPlayer() { + + // playbackManager needs this + this.name = PlayerName; + this.type = 'mediaplayer'; + this.id = 'chromecast'; + this.isLocalPlayer = false; + this.lastPlayerData = {}; + + castSenderApiLoader.load().then(initializeChromecast.bind(this)); + } + + ChromecastPlayer.prototype.tryPair = function (target) { + var castPlayer = this._castPlayer; - return castPlayer.deviceState !== DEVICE_STATE.ACTIVE && castPlayer.isInitialized ? new Promise(function(resolve, reject) { - currentResolve = resolve, currentReject = reject, castPlayer.launchApp() - }) : (currentResolve = null, currentReject = null, Promise.reject()) - }, ChromecastPlayer.prototype.getTargets = function() { + + if (castPlayer.deviceState !== DEVICE_STATE.ACTIVE && castPlayer.isInitialized) { + + return new Promise(function (resolve, reject) { + currentResolve = resolve; + currentReject = reject; + + castPlayer.launchApp(); + }); + } else { + + currentResolve = null; + currentReject = null; + + return Promise.reject(); + } + }; + + ChromecastPlayer.prototype.getTargets = function () { + var targets = []; - return this._castPlayer && this._castPlayer.hasReceivers && targets.push(this.getCurrentTargetInfo()), Promise.resolve(targets) - }, ChromecastPlayer.prototype.getCurrentTargetInfo = function() { - var appName = null, - castPlayer = this._castPlayer; - return castPlayer.session && castPlayer.session.receiver && castPlayer.session.receiver.friendlyName && (appName = castPlayer.session.receiver.friendlyName), { + + if (this._castPlayer && this._castPlayer.hasReceivers) { + targets.push(this.getCurrentTargetInfo()); + } + + return Promise.resolve(targets); + }; + + // This is a privately used method + ChromecastPlayer.prototype.getCurrentTargetInfo = function () { + + var appName = null; + + var castPlayer = this._castPlayer; + + if (castPlayer.session && castPlayer.session.receiver && castPlayer.session.receiver.friendlyName) { + appName = castPlayer.session.receiver.friendlyName; + } + + return { name: PlayerName, id: PlayerName, playerName: PlayerName, playableMediaTypes: ["Audio", "Video"], - isLocalPlayer: !1, + isLocalPlayer: false, appName: PlayerName, deviceName: appName, - supportedCommands: ["VolumeUp", "VolumeDown", "Mute", "Unmute", "ToggleMute", "SetVolume", "SetAudioStreamIndex", "SetSubtitleStreamIndex", "DisplayContent", "SetRepeatMode", "EndSession", "PlayMediaSource", "PlayTrailers"] + supportedCommands: [ + "VolumeUp", + "VolumeDown", + "Mute", + "Unmute", + "ToggleMute", + "SetVolume", + "SetAudioStreamIndex", + "SetSubtitleStreamIndex", + "DisplayContent", + "SetRepeatMode", + "EndSession", + "PlayMediaSource", + "PlayTrailers" + ] + }; + }; + + ChromecastPlayer.prototype.getPlayerStateInternal = function (data) { + + var triggerStateChange = false; + if (data && !this.lastPlayerData) { + triggerStateChange = true; } - }, ChromecastPlayer.prototype.getPlayerStateInternal = function(data) { - var triggerStateChange = !1; - return data && !this.lastPlayerData && (triggerStateChange = !0), data = data || this.lastPlayerData, this.lastPlayerData = data, normalizeImages(data), triggerStateChange && events.trigger(this, "statechange", [data]), data - }, ChromecastPlayer.prototype.playWithCommand = function(options, command) { + + data = data || this.lastPlayerData; + this.lastPlayerData = data; + + normalizeImages(data); + + //console.log(JSON.stringify(data)); + + if (triggerStateChange) { + events.trigger(this, "statechange", [data]); + } + + return data; + }; + + ChromecastPlayer.prototype.playWithCommand = function (options, command) { + if (!options.items) { - var apiClient = connectionManager.getApiClient(options.serverId), - instance = this; - return apiClient.getItem(apiClient.getCurrentUserId(), options.ids[0]).then(function(item) { - return options.items = [item], instance.playWithCommand(options, command) - }) + var apiClient = connectionManager.getApiClient(options.serverId); + var instance = this; + + return apiClient.getItem(apiClient.getCurrentUserId(), options.ids[0]).then(function (item) { + + options.items = [item]; + return instance.playWithCommand(options, command); + }); } - return this._castPlayer.loadMedia(options, command) - }, ChromecastPlayer.prototype.seek = function(position) { - position = parseInt(position), position /= 1e7, this._castPlayer.sendMessage({ + + return this._castPlayer.loadMedia(options, command); + }; + + ChromecastPlayer.prototype.seek = function (position) { + + position = parseInt(position); + + position = position / 10000000; + + this._castPlayer.sendMessage({ options: { position: position }, - command: "Seek" - }) - }, ChromecastPlayer.prototype.setAudioStreamIndex = function(index) { + command: 'Seek' + }); + }; + + ChromecastPlayer.prototype.setAudioStreamIndex = function (index) { this._castPlayer.sendMessage({ options: { index: index }, - command: "SetAudioStreamIndex" - }) - }, ChromecastPlayer.prototype.setSubtitleStreamIndex = function(index) { + command: 'SetAudioStreamIndex' + }); + }; + + ChromecastPlayer.prototype.setSubtitleStreamIndex = function (index) { this._castPlayer.sendMessage({ options: { index: index }, - command: "SetSubtitleStreamIndex" - }) - }, ChromecastPlayer.prototype.setMaxStreamingBitrate = function(options) { + command: 'SetSubtitleStreamIndex' + }); + }; + + ChromecastPlayer.prototype.setMaxStreamingBitrate = function (options) { + this._castPlayer.sendMessage({ options: options, - command: "SetMaxStreamingBitrate" - }) - }, ChromecastPlayer.prototype.isFullscreen = function() { + command: 'SetMaxStreamingBitrate' + }); + }; + + ChromecastPlayer.prototype.isFullscreen = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.IsFullscreen - }, ChromecastPlayer.prototype.nextTrack = function() { + state = state.PlayState || {}; + return state.IsFullscreen; + }; + + ChromecastPlayer.prototype.nextTrack = function () { this._castPlayer.sendMessage({ options: {}, - command: "NextTrack" - }) - }, ChromecastPlayer.prototype.previousTrack = function() { + command: 'NextTrack' + }); + }; + + ChromecastPlayer.prototype.previousTrack = function () { this._castPlayer.sendMessage({ options: {}, - command: "PreviousTrack" - }) - }, ChromecastPlayer.prototype.volumeDown = function() { + command: 'PreviousTrack' + }); + }; + + ChromecastPlayer.prototype.volumeDown = function () { + this._castPlayer.sendMessage({ options: {}, - command: "VolumeDown" - }) - }, ChromecastPlayer.prototype.endSession = function() { + command: 'VolumeDown' + }); + }; + + ChromecastPlayer.prototype.endSession = function () { + var instance = this; - this.stop().then(function() { - setTimeout(function() { - instance._castPlayer.stopApp() - }, 1e3) - }) - }, ChromecastPlayer.prototype.volumeUp = function() { + + this.stop().then(function () { + setTimeout(function () { + instance._castPlayer.stopApp(); + }, 1000); + }); + }; + + ChromecastPlayer.prototype.volumeUp = function () { + this._castPlayer.sendMessage({ options: {}, - command: "VolumeUp" - }) - }, ChromecastPlayer.prototype.setVolume = function(vol) { - vol = Math.min(vol, 100), vol = Math.max(vol, 0), this._castPlayer.sendMessage({ + command: 'VolumeUp' + }); + }; + + ChromecastPlayer.prototype.setVolume = function (vol) { + + vol = Math.min(vol, 100); + vol = Math.max(vol, 0); + + this._castPlayer.sendMessage({ options: { volume: vol }, - command: "SetVolume" - }) - }, ChromecastPlayer.prototype.unpause = function() { + command: 'SetVolume' + }); + }; + + ChromecastPlayer.prototype.unpause = function () { this._castPlayer.sendMessage({ options: {}, - command: "Unpause" - }) - }, ChromecastPlayer.prototype.playPause = function() { + command: 'Unpause' + }); + }; + + ChromecastPlayer.prototype.playPause = function () { this._castPlayer.sendMessage({ options: {}, - command: "PlayPause" - }) - }, ChromecastPlayer.prototype.pause = function() { + command: 'PlayPause' + }); + }; + + ChromecastPlayer.prototype.pause = function () { this._castPlayer.sendMessage({ options: {}, - command: "Pause" - }) - }, ChromecastPlayer.prototype.stop = function() { + command: 'Pause' + }); + }; + + ChromecastPlayer.prototype.stop = function () { return this._castPlayer.sendMessage({ options: {}, - command: "Stop" - }) - }, ChromecastPlayer.prototype.displayContent = function(options) { + command: 'Stop' + }); + }; + + ChromecastPlayer.prototype.displayContent = function (options) { + this._castPlayer.sendMessage({ options: options, - command: "DisplayContent" - }) - }, ChromecastPlayer.prototype.setMute = function(isMuted) { + command: 'DisplayContent' + }); + }; + + ChromecastPlayer.prototype.setMute = function (isMuted) { + var castPlayer = this._castPlayer; - isMuted ? castPlayer.sendMessage({ - options: {}, - command: "Mute" - }) : castPlayer.sendMessage({ - options: {}, - command: "Unmute" - }) - }, ChromecastPlayer.prototype.getRepeatMode = function() { + + if (isMuted) { + castPlayer.sendMessage({ + options: {}, + command: 'Mute' + }); + } else { + castPlayer.sendMessage({ + options: {}, + command: 'Unmute' + }); + } + }; + + ChromecastPlayer.prototype.getRepeatMode = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.RepeatMode - }, ChromecastPlayer.prototype.playTrailers = function(item) { + state = state.PlayState || {}; + return state.RepeatMode; + }; + + ChromecastPlayer.prototype.playTrailers = function (item) { + this._castPlayer.sendMessage({ options: { ItemId: item.Id, ServerId: item.ServerId }, - command: "PlayTrailers" - }) - }, ChromecastPlayer.prototype.setRepeatMode = function(mode) { + command: 'PlayTrailers' + }); + }; + + ChromecastPlayer.prototype.setRepeatMode = function (mode) { this._castPlayer.sendMessage({ options: { RepeatMode: mode }, - command: "SetRepeatMode" - }) - }, ChromecastPlayer.prototype.toggleMute = function() { + command: 'SetRepeatMode' + }); + }; + + ChromecastPlayer.prototype.toggleMute = function () { + this._castPlayer.sendMessage({ options: {}, - command: "ToggleMute" - }) - }, ChromecastPlayer.prototype.audioTracks = function() { + command: 'ToggleMute' + }); + }; + + ChromecastPlayer.prototype.audioTracks = function () { var state = this.lastPlayerData || {}; - return state = state.NowPlayingItem || {}, (state.MediaStreams || []).filter(function(s) { - return "Audio" === s.Type - }) - }, ChromecastPlayer.prototype.getAudioStreamIndex = function() { + state = state.NowPlayingItem || {}; + var streams = state.MediaStreams || []; + return streams.filter(function (s) { + return s.Type === 'Audio'; + }); + }; + + ChromecastPlayer.prototype.getAudioStreamIndex = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.AudioStreamIndex - }, ChromecastPlayer.prototype.subtitleTracks = function() { + state = state.PlayState || {}; + return state.AudioStreamIndex; + }; + + ChromecastPlayer.prototype.subtitleTracks = function () { var state = this.lastPlayerData || {}; - return state = state.NowPlayingItem || {}, (state.MediaStreams || []).filter(function(s) { - return "Subtitle" === s.Type - }) - }, ChromecastPlayer.prototype.getSubtitleStreamIndex = function() { + state = state.NowPlayingItem || {}; + var streams = state.MediaStreams || []; + return streams.filter(function (s) { + return s.Type === 'Subtitle'; + }); + }; + + ChromecastPlayer.prototype.getSubtitleStreamIndex = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.SubtitleStreamIndex - }, ChromecastPlayer.prototype.getMaxStreamingBitrate = function() { + state = state.PlayState || {}; + return state.SubtitleStreamIndex; + }; + + ChromecastPlayer.prototype.getMaxStreamingBitrate = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.MaxStreamingBitrate - }, ChromecastPlayer.prototype.getVolume = function() { + state = state.PlayState || {}; + return state.MaxStreamingBitrate; + }; + + ChromecastPlayer.prototype.getVolume = function () { + var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, null == state.VolumeLevel ? 100 : state.VolumeLevel - }, ChromecastPlayer.prototype.isPlaying = function() { - return null != (this.lastPlayerData || {}).NowPlayingItem - }, ChromecastPlayer.prototype.isPlayingVideo = function() { + state = state.PlayState || {}; + + return state.VolumeLevel == null ? 100 : state.VolumeLevel; + }; + + ChromecastPlayer.prototype.isPlaying = function () { var state = this.lastPlayerData || {}; - return state = state.NowPlayingItem || {}, "Video" === state.MediaType - }, ChromecastPlayer.prototype.isPlayingAudio = function() { + return state.NowPlayingItem != null; + }; + + ChromecastPlayer.prototype.isPlayingVideo = function () { var state = this.lastPlayerData || {}; - return state = state.NowPlayingItem || {}, "Audio" === state.MediaType - }, ChromecastPlayer.prototype.currentTime = function(val) { - if (null != val) return this.seek(val); + state = state.NowPlayingItem || {}; + return state.MediaType === 'Video'; + }; + + ChromecastPlayer.prototype.isPlayingAudio = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.PositionTicks - }, ChromecastPlayer.prototype.duration = function() { + state = state.NowPlayingItem || {}; + return state.MediaType === 'Audio'; + }; + + ChromecastPlayer.prototype.currentTime = function (val) { + + if (val != null) { + return this.seek(val); + } + var state = this.lastPlayerData || {}; - return state = state.NowPlayingItem || {}, state.RunTimeTicks - }, ChromecastPlayer.prototype.getBufferedRanges = function() { + state = state.PlayState || {}; + return state.PositionTicks; + }; + + ChromecastPlayer.prototype.duration = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.BufferedRanges || [] - }, ChromecastPlayer.prototype.paused = function() { + state = state.NowPlayingItem || {}; + return state.RunTimeTicks; + }; + + ChromecastPlayer.prototype.getBufferedRanges = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.IsPaused - }, ChromecastPlayer.prototype.isMuted = function() { + state = state.PlayState || {}; + return state.BufferedRanges || []; + }; + + ChromecastPlayer.prototype.paused = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.IsMuted - }, ChromecastPlayer.prototype.shuffle = function(item) { - var apiClient = connectionManager.getApiClient(item.ServerId), - userId = apiClient.getCurrentUserId(), - instance = this; - apiClient.getItem(userId, item.Id).then(function(item) { - instance.playWithCommand({ - items: [item] - }, "Shuffle") - }) - }, ChromecastPlayer.prototype.instantMix = function(item) { - var apiClient = connectionManager.getApiClient(item.ServerId), - userId = apiClient.getCurrentUserId(), - instance = this; - apiClient.getItem(userId, item.Id).then(function(item) { - instance.playWithCommand({ - items: [item] - }, "InstantMix") - }) - }, ChromecastPlayer.prototype.canPlayMediaType = function(mediaType) { - return "audio" === (mediaType = (mediaType || "").toLowerCase()) || "video" === mediaType - }, ChromecastPlayer.prototype.canQueueMediaType = function(mediaType) { - return this.canPlayMediaType(mediaType) - }, ChromecastPlayer.prototype.queue = function(options) { - this.playWithCommand(options, "PlayLast") - }, ChromecastPlayer.prototype.queueNext = function(options) { - this.playWithCommand(options, "PlayNext") - }, ChromecastPlayer.prototype.play = function(options) { - if (options.items) return this.playWithCommand(options, "PlayNow"); - if (!options.serverId) throw new Error("serverId required!"); + state = state.PlayState || {}; + + return state.IsPaused; + }; + + ChromecastPlayer.prototype.isMuted = function () { + var state = this.lastPlayerData || {}; + state = state.PlayState || {}; + + return state.IsMuted; + }; + + ChromecastPlayer.prototype.shuffle = function (item) { + + var apiClient = connectionManager.getApiClient(item.ServerId); + var userId = apiClient.getCurrentUserId(); + var instance = this; - return getItemsForPlayback(connectionManager.getApiClient(options.serverId), { - Ids: options.ids.join(",") - }).then(function(result) { - return options.items = result.Items, instance.playWithCommand(options, "PlayNow") - }) - }, ChromecastPlayer.prototype.toggleFullscreen = function() {}, ChromecastPlayer.prototype.beginPlayerUpdates = function() {}, ChromecastPlayer.prototype.endPlayerUpdates = function() {}, ChromecastPlayer.prototype.getPlaylist = function() { - return Promise.resolve([]) - }, ChromecastPlayer.prototype.getCurrentPlaylistItemId = function() {}, ChromecastPlayer.prototype.setCurrentPlaylistItem = function(playlistItemId) { - return Promise.resolve() - }, ChromecastPlayer.prototype.removeFromPlaylist = function(playlistItemIds) { - return Promise.resolve() - }, ChromecastPlayer.prototype.getPlayerState = function() { - return this.getPlayerStateInternal() || {} - }, ChromecastPlayer + + apiClient.getItem(userId, item.Id).then(function (item) { + + instance.playWithCommand({ + + items: [item] + + }, 'Shuffle'); + + }); + + }; + + ChromecastPlayer.prototype.instantMix = function (item) { + + var apiClient = connectionManager.getApiClient(item.ServerId); + var userId = apiClient.getCurrentUserId(); + + var instance = this; + + apiClient.getItem(userId, item.Id).then(function (item) { + + instance.playWithCommand({ + + items: [item] + + }, 'InstantMix'); + + }); + + }; + + ChromecastPlayer.prototype.canPlayMediaType = function (mediaType) { + + mediaType = (mediaType || '').toLowerCase(); + return mediaType === 'audio' || mediaType === 'video'; + }; + + ChromecastPlayer.prototype.canQueueMediaType = function (mediaType) { + return this.canPlayMediaType(mediaType); + }; + + ChromecastPlayer.prototype.queue = function (options) { + this.playWithCommand(options, 'PlayLast'); + }; + + ChromecastPlayer.prototype.queueNext = function (options) { + this.playWithCommand(options, 'PlayNext'); + }; + + ChromecastPlayer.prototype.play = function (options) { + + if (options.items) { + + return this.playWithCommand(options, 'PlayNow'); + + } else { + + if (!options.serverId) { + throw new Error('serverId required!'); + } + + var instance = this; + var apiClient = connectionManager.getApiClient(options.serverId); + + return getItemsForPlayback(apiClient, { + + Ids: options.ids.join(',') + + }).then(function (result) { + + options.items = result.Items; + return instance.playWithCommand(options, 'PlayNow'); + + }); + } + }; + + ChromecastPlayer.prototype.toggleFullscreen = function () { + // not supported + }; + + ChromecastPlayer.prototype.beginPlayerUpdates = function () { + // Setup polling here + }; + + ChromecastPlayer.prototype.endPlayerUpdates = function () { + // Stop polling here + }; + + ChromecastPlayer.prototype.getPlaylist = function () { + return Promise.resolve([]); + }; + + ChromecastPlayer.prototype.getCurrentPlaylistItemId = function () { + }; + + ChromecastPlayer.prototype.setCurrentPlaylistItem = function (playlistItemId) { + return Promise.resolve(); + }; + + ChromecastPlayer.prototype.removeFromPlaylist = function (playlistItemIds) { + return Promise.resolve(); + }; + + ChromecastPlayer.prototype.getPlayerState = function () { + + return this.getPlayerStateInternal() || {}; + }; + + return ChromecastPlayer; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/clearbutton.css b/src/bower_components/emby-webcomponents/clearbutton.css index e41da78a3e..2d3f8d6800 100644 --- a/src/bower_components/emby-webcomponents/clearbutton.css +++ b/src/bower_components/emby-webcomponents/clearbutton.css @@ -1,12 +1,12 @@ .clearButton { - background: 0 0; + background: transparent; border: 0 !important; padding: 0 !important; cursor: pointer; - outline: 0 !important; + outline: none !important; color: inherit; width: 100%; vertical-align: middle; font-family: inherit; - font-size: inherit + font-size: inherit; } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/collectioneditor/collectioneditor.js b/src/bower_components/emby-webcomponents/collectioneditor/collectioneditor.js index d1aeec3c8e..8e526fa114 100644 --- a/src/bower_components/emby-webcomponents/collectioneditor/collectioneditor.js +++ b/src/bower_components/emby-webcomponents/collectioneditor/collectioneditor.js @@ -1,119 +1,287 @@ -define(["dialogHelper", "loading", "apphost", "layoutManager", "connectionManager", "appRouter", "globalize", "emby-checkbox", "emby-input", "paper-icon-button-light", "emby-select", "material-icons", "css!./../formdialog", "emby-button", "emby-linkbutton", "flexStyles"], function(dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) { - "use strict"; +define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) { + 'use strict'; + + var currentServerId; function parentWithClass(elem, className) { - for (; !elem.classList || !elem.classList.contains(className);) - if (!(elem = elem.parentNode)) return null; - return elem + + while (!elem.classList || !elem.classList.contains(className)) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; } function onSubmit(e) { loading.show(); - var panel = parentWithClass(this, "dialog"), - collectionId = panel.querySelector("#selectCollectionToAddTo").value, - apiClient = connectionManager.getApiClient(currentServerId); - return collectionId ? addToCollection(apiClient, panel, collectionId) : createCollection(apiClient, panel), e.preventDefault(), !1 + + var panel = parentWithClass(this, 'dialog'); + + var collectionId = panel.querySelector('#selectCollectionToAddTo').value; + + var apiClient = connectionManager.getApiClient(currentServerId); + + if (collectionId) { + addToCollection(apiClient, panel, collectionId); + } else { + createCollection(apiClient, panel); + } + + e.preventDefault(); + return false; } function createCollection(apiClient, dlg) { + var url = apiClient.getUrl("Collections", { - Name: dlg.querySelector("#txtNewCollectionName").value, - IsLocked: !dlg.querySelector("#chkEnableInternetMetadata").checked, - Ids: dlg.querySelector(".fldSelectedItemIds").value || "" + + Name: dlg.querySelector('#txtNewCollectionName').value, + IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked, + Ids: dlg.querySelector('.fldSelectedItemIds').value || '' }); + apiClient.ajax({ type: "POST", url: url, dataType: "json" - }).then(function(result) { + + }).then(function (result) { + loading.hide(); + var id = result.Id; - dlg.submitted = !0, dialogHelper.close(dlg), redirectToCollection(apiClient, id) - }) + + dlg.submitted = true; + dialogHelper.close(dlg); + redirectToCollection(apiClient, id); + + }); } function redirectToCollection(apiClient, id) { - appRouter.showItem(id, apiClient.serverId()) + + appRouter.showItem(id, apiClient.serverId()); } function addToCollection(apiClient, dlg, id) { + var url = apiClient.getUrl("Collections/" + id + "/Items", { - Ids: dlg.querySelector(".fldSelectedItemIds").value || "" + + Ids: dlg.querySelector('.fldSelectedItemIds').value || '' }); + apiClient.ajax({ type: "POST", url: url - }).then(function() { - loading.hide(), dlg.submitted = !0, dialogHelper.close(dlg), require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#MessageItemsAdded")) - }) - }) + + }).then(function () { + + loading.hide(); + + dlg.submitted = true; + dialogHelper.close(dlg); + + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#MessageItemsAdded')); + }); + }); } function triggerChange(select) { - select.dispatchEvent(new CustomEvent("change", {})) + select.dispatchEvent(new CustomEvent('change', {})); } function populateCollections(panel) { + loading.show(); - var select = panel.querySelector("#selectCollectionToAddTo"); - panel.querySelector(".newCollectionInfo").classList.add("hide"); + + var select = panel.querySelector('#selectCollectionToAddTo'); + + panel.querySelector('.newCollectionInfo').classList.add('hide'); + var options = { - Recursive: !0, - IncludeItemTypes: "BoxSet", - SortBy: "SortName", - EnableTotalRecordCount: !1 - }, - apiClient = connectionManager.getApiClient(currentServerId); - apiClient.getItems(apiClient.getCurrentUserId(), options).then(function(result) { - var html = ""; - html += '", html += result.Items.map(function(i) { - return '" - }), select.innerHTML = html, select.value = "", triggerChange(select), loading.hide() - }) + + Recursive: true, + IncludeItemTypes: "BoxSet", + SortBy: "SortName", + EnableTotalRecordCount: false + }; + + var apiClient = connectionManager.getApiClient(currentServerId); + apiClient.getItems(apiClient.getCurrentUserId(), options).then(function (result) { + + var html = ''; + + html += ''; + + html += result.Items.map(function (i) { + + return ''; + }); + + select.innerHTML = html; + select.value = ''; + triggerChange(select); + + loading.hide(); + }); } function getEditorHtml() { - var html = ""; - return html += '
', html += '
', html += '
', html += "
", html += globalize.translate("sharedcomponents#NewCollectionHelp"), html += "
", html += '
', html += "
", html += "
", html += '
', html += '', html += "
", html += "
", html += '
', html += '
', html += '', html += '
' + globalize.translate("sharedcomponents#NewCollectionNameExample") + "
", html += "
", html += '", html += "
", html += '
', html += '", html += "
", html += '', html += "
", html += "
", html += "
" + + var html = ''; + + html += '
'; + html += '
'; + html += '
'; + + html += '
'; + html += globalize.translate('sharedcomponents#NewCollectionHelp'); + html += '
'; + + html += '
'; + html += '
'; + html += '
'; + html += '
'; + html += ''; + html += '
'; + html += '
'; + + html += '
'; + + html += '
'; + html += ''; + html += '
' + globalize.translate('sharedcomponents#NewCollectionNameExample') + '
'; + html += '
'; + + html += ''; + + // newCollectionInfo + html += '
'; + + html += '
'; + html += ''; + html += '
'; + + html += ''; + + html += '
'; + html += '
'; + html += '
'; + + return html; } function initEditor(content, items) { - if (content.querySelector("#selectCollectionToAddTo").addEventListener("change", function() { - this.value ? (content.querySelector(".newCollectionInfo").classList.add("hide"), content.querySelector("#txtNewCollectionName").removeAttribute("required")) : (content.querySelector(".newCollectionInfo").classList.remove("hide"), content.querySelector("#txtNewCollectionName").setAttribute("required", "required")) - }), content.querySelector("form").addEventListener("submit", onSubmit), content.querySelector(".fldSelectedItemIds", content).value = items.join(","), items.length) content.querySelector(".fldSelectCollection").classList.remove("hide"), populateCollections(content); - else { - content.querySelector(".fldSelectCollection").classList.add("hide"); - var selectCollectionToAddTo = content.querySelector("#selectCollectionToAddTo"); - selectCollectionToAddTo.innerHTML = "", selectCollectionToAddTo.value = "", triggerChange(selectCollectionToAddTo) + + content.querySelector('#selectCollectionToAddTo').addEventListener('change', function () { + if (this.value) { + content.querySelector('.newCollectionInfo').classList.add('hide'); + content.querySelector('#txtNewCollectionName').removeAttribute('required'); + } else { + content.querySelector('.newCollectionInfo').classList.remove('hide'); + content.querySelector('#txtNewCollectionName').setAttribute('required', 'required'); + } + }); + + content.querySelector('form').addEventListener('submit', onSubmit); + + content.querySelector('.fldSelectedItemIds', content).value = items.join(','); + + if (items.length) { + content.querySelector('.fldSelectCollection').classList.remove('hide'); + populateCollections(content); + } else { + content.querySelector('.fldSelectCollection').classList.add('hide'); + + var selectCollectionToAddTo = content.querySelector('#selectCollectionToAddTo'); + selectCollectionToAddTo.innerHTML = ''; + selectCollectionToAddTo.value = ''; + triggerChange(selectCollectionToAddTo); } } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } - function CollectionEditor() {} - var currentServerId; - return CollectionEditor.prototype.show = function(options) { + function CollectionEditor() { + + } + + CollectionEditor.prototype.show = function (options) { + var items = options.items || {}; currentServerId = options.serverId; + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'small'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - var html = "", - title = items.length ? globalize.translate("sharedcomponents#HeaderAddToCollection") : globalize.translate("sharedcomponents#NewCollection"); - return html += '
', html += '', html += '

', html += title, html += "

", appHost.supports("externallinks") && (html += '' + globalize.translate("sharedcomponents#Help") + ""), html += "
", html += getEditorHtml(), dlg.innerHTML = html, initEditor(dlg, items), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), dialogHelper.open(dlg).then(function() { - return layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), dlg.submitted ? Promise.resolve() : Promise.reject() - }) - }, CollectionEditor + + dlg.classList.add('formDialog'); + + var html = ''; + var title = items.length ? globalize.translate('sharedcomponents#HeaderAddToCollection') : globalize.translate('sharedcomponents#NewCollection'); + + html += '
'; + html += ''; + html += '

'; + html += title; + html += '

'; + + if (appHost.supports('externallinks')) { + html += '' + globalize.translate('sharedcomponents#Help') + ''; + } + + html += '
'; + + html += getEditorHtml(); + + dlg.innerHTML = html; + + initEditor(dlg, items); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + + return dialogHelper.open(dlg).then(function () { + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + if (dlg.submitted) { + return Promise.resolve(); + } + + return Promise.reject(); + }); + }; + + return CollectionEditor; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/confirm/confirm.js b/src/bower_components/emby-webcomponents/confirm/confirm.js index 22890d52cb..877a0716e9 100644 --- a/src/bower_components/emby-webcomponents/confirm/confirm.js +++ b/src/bower_components/emby-webcomponents/confirm/confirm.js @@ -1,22 +1,40 @@ -define(["dialog", "globalize"], function(dialog, globalize) { - "use strict"; - return function(text, title) { +define(['dialog', 'globalize'], function (dialog, globalize) { + 'use strict'; + + return function (text, title) { + var options; - options = "string" == typeof text ? { - title: title, - text: text - } : text; + if (typeof text === 'string') { + options = { + title: title, + text: text + }; + } else { + options = text; + } + var items = []; - return items.push({ - name: options.cancelText || globalize.translate("sharedcomponents#ButtonCancel"), - id: "cancel", - type: "cancel" === options.primary ? "submit" : "cancel" - }), items.push({ - name: options.confirmText || globalize.translate("sharedcomponents#ButtonOk"), - id: "ok", - type: "cancel" === options.primary ? "cancel" : "submit" - }), options.buttons = items, dialog(options).then(function(result) { - return "ok" === result ? Promise.resolve() : Promise.reject() - }) - } + + items.push({ + name: options.cancelText || globalize.translate('sharedcomponents#ButtonCancel'), + id: 'cancel', + type: options.primary === 'cancel' ? 'submit' : 'cancel' + }); + + items.push({ + name: options.confirmText || globalize.translate('sharedcomponents#ButtonOk'), + id: 'ok', + type: options.primary === 'cancel' ? 'cancel' : 'submit' + }); + + options.buttons = items; + + return dialog(options).then(function (result) { + if (result === 'ok') { + return Promise.resolve(); + } + + return Promise.reject(); + }); + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/confirm/nativeconfirm.js b/src/bower_components/emby-webcomponents/confirm/nativeconfirm.js index d909e687e8..fd586ad1d5 100644 --- a/src/bower_components/emby-webcomponents/confirm/nativeconfirm.js +++ b/src/bower_components/emby-webcomponents/confirm/nativeconfirm.js @@ -1,15 +1,27 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; function replaceAll(str, find, replace) { - return str.split(find).join(replace) - } - return function(options) { - "string" == typeof options && (options = { - title: "", - text: options - }); - var text = replaceAll(options.text || "", "
", "\n"); - return confirm(text) ? Promise.resolve() : Promise.reject() + + return str.split(find).join(replace); } + + return function (options) { + + if (typeof options === 'string') { + options = { + title: '', + text: options + }; + } + + var text = replaceAll(options.text || '', '
', '\n'); + var result = confirm(text); + + if (result) { + return Promise.resolve(); + } else { + return Promise.reject(); + } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/datetime.js b/src/bower_components/emby-webcomponents/datetime.js index 9d3edd6786..15d0c64865 100644 --- a/src/bower_components/emby-webcomponents/datetime.js +++ b/src/bower_components/emby-webcomponents/datetime.js @@ -1,113 +1,272 @@ -define(["globalize"], function(globalize) { - "use strict"; +define(['globalize'], function (globalize) { + 'use strict'; function parseISO8601Date(s, toLocal) { - var re = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))?/, - d = s.match(re); - if (!d) throw "Couldn't parse ISO 8601 date string '" + s + "'"; + + // parenthese matches: + // year month day hours minutes seconds + // dotmilliseconds + // tzstring plusminus hours minutes + var re = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))?/; + + var d = s.match(re); + + // "2010-12-07T11:00:00.000-09:00" parses to: + // ["2010-12-07T11:00:00.000-09:00", "2010", "12", "07", "11", + // "00", "00", ".000", "-09:00", "-", "09", "00"] + // "2010-12-07T11:00:00.000Z" parses to: + // ["2010-12-07T11:00:00.000Z", "2010", "12", "07", "11", + // "00", "00", ".000", "Z", undefined, undefined, undefined] + + if (!d) { + + throw "Couldn't parse ISO 8601 date string '" + s + "'"; + } + + // parse strings, leading zeros into proper ints var a = [1, 2, 3, 4, 5, 6, 10, 11]; - for (var i in a) d[a[i]] = parseInt(d[a[i]], 10); + for (var i in a) { + d[a[i]] = parseInt(d[a[i]], 10); + } d[7] = parseFloat(d[7]); + + // Date.UTC(year, month[, date[, hrs[, min[, sec[, ms]]]]]) + // note that month is 0-11, not 1-12 + // see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/UTC var ms = Date.UTC(d[1], d[2] - 1, d[3], d[4], d[5], d[6]); - if (d[7] > 0 && (ms += Math.round(1e3 * d[7])), "Z" !== d[8] && d[10]) { - var offset = 60 * d[10] * 60 * 1e3; - d[11] && (offset += 60 * d[11] * 1e3), "-" === d[9] ? ms -= offset : ms += offset - } else !1 === toLocal && (ms += 6e4 * (new Date).getTimezoneOffset()); - return new Date(ms) + + // if there are milliseconds, add them + if (d[7] > 0) { + ms += Math.round(d[7] * 1000); + } + + // if there's a timezone, calculate it + if (d[8] !== "Z" && d[10]) { + var offset = d[10] * 60 * 60 * 1000; + if (d[11]) { + offset += d[11] * 60 * 1000; + } + if (d[9] === "-") { + ms -= offset; + } else { + ms += offset; + } + } else if (toLocal === false) { + ms += new Date().getTimezoneOffset() * 60000; + } + + return new Date(ms); } function getDisplayRunningTime(ticks) { - var parts = [], - hours = ticks / 36e9; - hours = Math.floor(hours), hours && parts.push(hours), ticks -= 36e9 * hours; - var minutes = ticks / 6e8; - minutes = Math.floor(minutes), ticks -= 6e8 * minutes, minutes < 10 && hours && (minutes = "0" + minutes), parts.push(minutes); - var seconds = ticks / 1e7; - return seconds = Math.floor(seconds), seconds < 10 && (seconds = "0" + seconds), parts.push(seconds), parts.join(":") + var ticksPerHour = 36000000000; + var ticksPerMinute = 600000000; + var ticksPerSecond = 10000000; + + var parts = []; + + var hours = ticks / ticksPerHour; + hours = Math.floor(hours); + + if (hours) { + parts.push(hours); + } + + ticks -= (hours * ticksPerHour); + + var minutes = ticks / ticksPerMinute; + minutes = Math.floor(minutes); + + ticks -= (minutes * ticksPerMinute); + + if (minutes < 10 && hours) { + minutes = '0' + minutes; + } + parts.push(minutes); + + var seconds = ticks / ticksPerSecond; + seconds = Math.floor(seconds); + + if (seconds < 10) { + seconds = '0' + seconds; + } + parts.push(seconds); + + return parts.join(':'); } + var toLocaleTimeStringSupportsLocales = function () { + try { + new Date().toLocaleTimeString('i'); + } catch (e) { + return e.name === 'RangeError'; + } + return false; + }(); + function getOptionList(options) { + var list = []; - for (var i in options) list.push({ - name: i, - value: options[i] - }); - return list + + for (var i in options) { + list.push({ + name: i, + value: options[i] + }); + } + + return list; } function toLocaleString(date, options) { - if (!date) throw new Error("date cannot be null"); - if (options = options || {}, toLocaleTimeStringSupportsLocales) { - var currentLocale = globalize.getCurrentDateTimeLocale(); - if (currentLocale) return date.toLocaleString(currentLocale, options) + + if (!date) { + throw new Error('date cannot be null'); } - return date.toLocaleString() + + options = options || {}; + + if (toLocaleTimeStringSupportsLocales) { + + var currentLocale = globalize.getCurrentDateTimeLocale(); + + if (currentLocale) { + return date.toLocaleString(currentLocale, options); + } + } + + return date.toLocaleString(); } function toLocaleDateString(date, options) { - if (!date) throw new Error("date cannot be null"); - if (options = options || {}, toLocaleTimeStringSupportsLocales) { + + if (!date) { + throw new Error('date cannot be null'); + } + + options = options || {}; + + if (toLocaleTimeStringSupportsLocales) { + var currentLocale = globalize.getCurrentDateTimeLocale(); - if (currentLocale) return date.toLocaleDateString(currentLocale, options) + + if (currentLocale) { + return date.toLocaleDateString(currentLocale, options); + } } + + // This is essentially a hard-coded polyfill var optionList = getOptionList(options); - if (1 === optionList.length && "weekday" === optionList[0].name) { + if (optionList.length === 1 && optionList[0].name === 'weekday') { var weekday = []; - return weekday[0] = "Sun", weekday[1] = "Mon", weekday[2] = "Tue", weekday[3] = "Wed", weekday[4] = "Thu", weekday[5] = "Fri", weekday[6] = "Sat", weekday[date.getDay()] + 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() + + return date.toLocaleDateString(); } function toLocaleTimeString(date, options) { - if (!date) throw new Error("date cannot be null"); - if (options = options || {}, toLocaleTimeStringSupportsLocales) { - var currentLocale = globalize.getCurrentDateTimeLocale(); - if (currentLocale) return date.toLocaleTimeString(currentLocale, options) + + if (!date) { + throw new Error('date cannot be null'); } - return date.toLocaleTimeString() + + options = options || {}; + + if (toLocaleTimeStringSupportsLocales) { + + var currentLocale = globalize.getCurrentDateTimeLocale(); + + if (currentLocale) { + return date.toLocaleTimeString(currentLocale, options); + } + } + + return date.toLocaleTimeString(); } function getDisplayTime(date) { - if (!date) throw new Error("date cannot be null"); - if ("string" === (typeof date).toString().toLowerCase()) try { - date = parseISO8601Date(date, !0) - } catch (err) { - return date + + if (!date) { + throw new Error('date cannot be null'); } - if (toLocaleTimeStringSupportsLocales) return toLocaleTimeString(date, { - hour: "numeric", - minute: "2-digit" - }); - var time = toLocaleTimeString(date), - timeLower = time.toLowerCase(); - if (-1 !== timeLower.indexOf("am") || -1 !== timeLower.indexOf("pm")) { + + if ((typeof date).toString().toLowerCase() === 'string') { + try { + + date = parseISO8601Date(date, true); + + } catch (err) { + return date; + } + } + + if (toLocaleTimeStringSupportsLocales) { + return toLocaleTimeString(date, { + + hour: 'numeric', + minute: '2-digit' + + }); + } + + var time = toLocaleTimeString(date); + + var timeLower = time.toLowerCase(); + + if (timeLower.indexOf('am') !== -1 || timeLower.indexOf('pm') !== -1) { + time = timeLower; - var hour = date.getHours() % 12, - suffix = date.getHours() > 11 ? "pm" : "am"; - hour || (hour = 12); + var hour = date.getHours() % 12; + var suffix = date.getHours() > 11 ? 'pm' : 'am'; + if (!hour) { + hour = 12; + } var minutes = date.getMinutes(); - minutes < 10 && (minutes = "0" + minutes), minutes = ":" + minutes, time = hour + minutes + suffix + + if (minutes < 10) { + minutes = '0' + minutes; + } + + minutes = ':' + minutes; + time = hour + minutes + suffix; } else { - var timeParts = time.split(":"); - timeParts.length > 2 && (timeParts.length = 2, time = timeParts.join(":")) + + var timeParts = time.split(':'); + + // Trim off seconds + if (timeParts.length > 2) { + + // setting to 2 also handles '21:00:28 GMT+9:30' + timeParts.length = 2; + time = timeParts.join(':'); + } } - return time + + return time; } function isRelativeDay(date, offsetInDays) { - if (!date) throw new Error("date cannot be null"); - var yesterday = new Date, - day = yesterday.getDate() + offsetInDays; - return yesterday.setDate(day), date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === day - } - var toLocaleTimeStringSupportsLocales = function() { - try { - (new Date).toLocaleTimeString("i") - } catch (e) { - return "RangeError" === e.name + + if (!date) { + throw new Error('date cannot be null'); } - return !1 - }(); + + var yesterday = new Date(); + var day = yesterday.getDate() + offsetInDays; + + yesterday.setDate(day); // automatically adjusts month/year appropriately + + return date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === day; + } + return { parseISO8601Date: parseISO8601Date, getDisplayRunningTime: getDisplayRunningTime, @@ -116,8 +275,8 @@ define(["globalize"], function(globalize) { getDisplayTime: getDisplayTime, isRelativeDay: isRelativeDay, toLocaleTimeString: toLocaleTimeString, - supportsLocalization: function() { - return toLocaleTimeStringSupportsLocales + supportsLocalization: function () { + return toLocaleTimeStringSupportsLocales; } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/deletehelper.js b/src/bower_components/emby-webcomponents/deletehelper.js index e31b9104e3..e8f3ad3d18 100644 --- a/src/bower_components/emby-webcomponents/deletehelper.js +++ b/src/bower_components/emby-webcomponents/deletehelper.js @@ -1,39 +1,57 @@ -define(["connectionManager", "confirm", "appRouter", "globalize"], function(connectionManager, confirm, appRouter, globalize) { - "use strict"; +define(['connectionManager', 'confirm', 'appRouter', 'globalize'], function (connectionManager, confirm, appRouter, globalize) { + 'use strict'; function alertText(options) { - return new Promise(function(resolve, reject) { - require(["alert"], function(alert) { - alert(options).then(resolve, resolve) - }) - }) + + return new Promise(function (resolve, reject) { + + require(['alert'], function (alert) { + alert(options).then(resolve, resolve); + }); + }); } function deleteItem(options) { - var item = options.item, - itemId = item.Id, - parentId = item.SeasonId || item.SeriesId || item.ParentId, - serverId = item.ServerId, - msg = globalize.translate("sharedcomponents#ConfirmDeleteItem"), - title = globalize.translate("sharedcomponents#HeaderDeleteItem"), - apiClient = connectionManager.getApiClient(item.ServerId); + + 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() { - options.navigate && (parentId ? appRouter.showItem(parentId, serverId) : appRouter.goHome()) - }, function(err) { - var result = function() { - return Promise.reject(err) + confirmText: globalize.translate('sharedcomponents#Delete'), + primary: 'cancel' + + }).then(function () { + + return apiClient.deleteItem(itemId).then(function () { + + if (options.navigate) { + if (parentId) { + appRouter.showItem(parentId, serverId); + } else { + appRouter.goHome(); + } + } + }, function (err) { + + var result = function () { + return Promise.reject(err); }; - return alertText(globalize.translate("sharedcomponents#ErrorDeletingItem")).then(result, result) - }) - }) + + return alertText(globalize.translate('sharedcomponents#ErrorDeletingItem')).then(result, result); + }); + }); } + return { deleteItem: deleteItem - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/dialog/dialog.js b/src/bower_components/emby-webcomponents/dialog/dialog.js index 1208719886..62faebd31e 100644 --- a/src/bower_components/emby-webcomponents/dialog/dialog.js +++ b/src/bower_components/emby-webcomponents/dialog/dialog.js @@ -1,46 +1,133 @@ -define(["dialogHelper", "dom", "layoutManager", "scrollHelper", "globalize", "require", "material-icons", "emby-button", "paper-icon-button-light", "emby-input", "formDialogStyle", "flexStyles"], function(dialogHelper, dom, layoutManager, scrollHelper, globalize, require) { - "use strict"; +define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (dialogHelper, dom, layoutManager, scrollHelper, globalize, require) { + 'use strict'; function showDialog(options, template) { - function onButtonClick() { - dialogResult = this.getAttribute("data-id"), dialogHelper.close(dlg) - } + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 - }, - enableTvLayout = layoutManager.tv; - enableTvLayout && (dialogOptions.size = "fullscreen"); - var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateHtml(template, "sharedcomponents"), dlg.classList.add("align-items-center"), dlg.classList.add("justify-content-center"); - var formDialogContent = dlg.querySelector(".formDialogContent"); - formDialogContent.classList.add("no-grow"), enableTvLayout ? (formDialogContent.style["max-width"] = "50%", formDialogContent.style["max-height"] = "60%", scrollHelper.centerFocus.on(formDialogContent, !1)) : (formDialogContent.style.maxWidth = Math.min(150 * options.buttons.length + 200, dom.getWindowSize().innerWidth - 50) + "px", dlg.classList.add("dialog-fullscreen-lowres")), options.title ? dlg.querySelector(".formDialogHeaderTitle").innerHTML = options.title || "" : dlg.querySelector(".formDialogHeaderTitle").classList.add("hide"); - var displayText = options.html || options.text || ""; - dlg.querySelector(".text").innerHTML = displayText, displayText || dlg.querySelector(".dialogContentInner").classList.add("hide"); - var i, length, html = "", - hasDescriptions = !1; - for (i = 0, length = options.buttons.length; i < length; i++) { - var item = options.buttons[i], - autoFocus = 0 === i ? " autofocus" : "", - buttonClass = "btnOption raised formDialogFooterItem formDialogFooterItem-autosize"; - item.type && (buttonClass += " button-" + item.type), item.description && (hasDescriptions = !0), hasDescriptions && (buttonClass += " formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom"), html += '", item.description && (html += '
' + item.description + "
") + removeOnClose: true, + scrollY: false + }; + + var enableTvLayout = layoutManager.tv; + + if (enableTvLayout) { + dialogOptions.size = 'fullscreen'; } - dlg.querySelector(".formDialogFooter").innerHTML = html, hasDescriptions && dlg.querySelector(".formDialogFooter").classList.add("formDialogFooter-vertical"); - var dialogResult, buttons = dlg.querySelectorAll(".btnOption"); - for (i = 0, length = buttons.length; i < length; i++) buttons[i].addEventListener("click", onButtonClick); - return dialogHelper.open(dlg).then(function() { - return enableTvLayout && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), dialogResult || Promise.reject() - }) + + var dlg = dialogHelper.createDialog(dialogOptions); + + dlg.classList.add('formDialog'); + + dlg.innerHTML = globalize.translateHtml(template, 'sharedcomponents'); + + dlg.classList.add('align-items-center'); + dlg.classList.add('justify-content-center'); + var formDialogContent = dlg.querySelector('.formDialogContent'); + formDialogContent.classList.add('no-grow'); + + if (enableTvLayout) { + formDialogContent.style['max-width'] = '50%'; + formDialogContent.style['max-height'] = '60%'; + scrollHelper.centerFocus.on(formDialogContent, false); + } else { + formDialogContent.style.maxWidth = (Math.min((options.buttons.length * 150) + 200, dom.getWindowSize().innerWidth - 50)) + 'px'; + dlg.classList.add('dialog-fullscreen-lowres'); + } + + //dlg.querySelector('.btnCancel').addEventListener('click', function (e) { + // dialogHelper.close(dlg); + //}); + + if (options.title) { + dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || ''; + } else { + dlg.querySelector('.formDialogHeaderTitle').classList.add('hide'); + } + + var displayText = options.html || options.text || ''; + dlg.querySelector('.text').innerHTML = displayText; + + if (!displayText) { + dlg.querySelector('.dialogContentInner').classList.add('hide'); + } + + var i, length; + var html = ''; + var hasDescriptions = false; + + for (i = 0, length = options.buttons.length; i < length; i++) { + + var item = options.buttons[i]; + var autoFocus = i === 0 ? ' autofocus' : ''; + + var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize'; + + if (item.type) { + buttonClass += ' button-' + item.type; + } + + if (item.description) { + hasDescriptions = true; + } + + if (hasDescriptions) { + buttonClass += ' formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom'; + } + + html += ''; + + if (item.description) { + html += '
' + item.description + '
'; + } + } + + dlg.querySelector('.formDialogFooter').innerHTML = html; + + if (hasDescriptions) { + dlg.querySelector('.formDialogFooter').classList.add('formDialogFooter-vertical'); + } + + var dialogResult; + function onButtonClick() { + dialogResult = this.getAttribute('data-id'); + dialogHelper.close(dlg); + } + + var buttons = dlg.querySelectorAll('.btnOption'); + for (i = 0, length = buttons.length; i < length; i++) { + buttons[i].addEventListener('click', onButtonClick); + } + + return dialogHelper.open(dlg).then(function () { + + if (enableTvLayout) { + scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); + } + + if (dialogResult) { + return dialogResult; + } else { + return Promise.reject(); + } + }); } - return function(text, title) { + + return function (text, title) { + var options; - return options = "string" == typeof text ? { - title: title, - text: text - } : text, new Promise(function(resolve, reject) { - require(["text!./dialog.template.html"], function(template) { - showDialog(options, template).then(resolve, reject) - }) - }) - } + if (typeof text === 'string') { + options = { + title: title, + text: text + }; + } else { + options = text; + } + + return new Promise(function (resolve, reject) { + require(['text!./dialog.template.html'], function (template) { + showDialog(options, template).then(resolve, reject); + }); + }); + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.css b/src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.css index c396dec604..2cc20b5ff2 100644 --- a/src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.css +++ b/src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.css @@ -1,12 +1,6 @@ .dialogContainer { - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; position: fixed; top: 0; @@ -16,234 +10,148 @@ z-index: 999999 !important; contain: strict; overflow: hidden; - overscroll-behavior: contain + overscroll-behavior: contain; } .dialog { margin: 0; - -webkit-border-radius: .2em; border-radius: .2em; -webkit-font-smoothing: antialiased; border: 0; padding: 0; will-change: transform, opacity; + /* Strict does not work well with actionsheet */ contain: style paint; - -webkit-box-shadow: 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12), 0 8px 10px -5px rgba(0, 0, 0, .4); - box-shadow: 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12), 0 8px 10px -5px rgba(0, 0, 0, .4) + box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.4); } .dialog-fixedSize { - -webkit-border-radius: 0; border-radius: 0; max-height: none; max-width: none; - contain: layout style paint + contain: layout style paint; } .dialog-fullscreen { + /* Needed due to formDialog style */ position: fixed !important; top: 0; bottom: 0; left: 0; right: 0; margin: 0; - -webkit-box-shadow: none; - box-shadow: none -} - -@-webkit-keyframes scaledown { - from { - opacity: 1; - -webkit-transform: none; - transform: none - } - - to { - opacity: 0; - -webkit-transform: scale(.5); - transform: scale(.5) - } + box-shadow: none; } @keyframes scaledown { from { opacity: 1; - -webkit-transform: none; - transform: none + transform: none; } to { opacity: 0; - -webkit-transform: scale(.5); - transform: scale(.5) - } -} - -@-webkit-keyframes scaleup { - from { - -webkit-transform: scale(.5); transform: scale(.5); - opacity: 0 - } - - to { - -webkit-transform: none; - transform: none; - opacity: 1 } } @keyframes scaleup { from { - -webkit-transform: scale(.5); transform: scale(.5); - opacity: 0 + opacity: 0; } to { - -webkit-transform: none; transform: none; - opacity: 1 - } -} - -@-webkit-keyframes fadein { - from { - opacity: 0 - } - - to { - opacity: 1 + opacity: 1; } } @keyframes fadein { - from { - opacity: 0 - } - - to { - opacity: 1 - } -} - -@-webkit-keyframes fadeout { - from { - opacity: 1 - } - - to { - opacity: 0 - } -} - -@keyframes fadeout { - from { - opacity: 1 - } - - to { - opacity: 0 - } -} - -@-webkit-keyframes slideup { from { opacity: 0; - -webkit-transform: translate3d(0, 30%, 0); - transform: translate3d(0, 30%, 0) } to { opacity: 1; - -webkit-transform: none; - transform: none + } +} + +@keyframes fadeout { + + from { + opacity: 1; + } + + to { + opacity: 0; } } @keyframes slideup { from { opacity: 0; - -webkit-transform: translate3d(0, 30%, 0); - transform: translate3d(0, 30%, 0) + transform: translate3d(0, 30%, 0); } to { opacity: 1; - -webkit-transform: none; - transform: none - } -} - -@-webkit-keyframes slidedown { - from { - opacity: 1; - -webkit-transform: none; - transform: none - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 20%, 0); - transform: translate3d(0, 20%, 0) + transform: none; } } @keyframes slidedown { + from { opacity: 1; - -webkit-transform: none; - transform: none + transform: none; } to { opacity: 0; - -webkit-transform: translate3d(0, 20%, 0); - transform: translate3d(0, 20%, 0) + transform: translate3d(0, 20%, 0); } } -@media all and (max-width:80em), -all and (max-height:45em) { +@media all and (max-width: 80em), all and (max-height: 45em) { - .dialog-fixedSize, - .dialog-fullscreen-lowres { + .dialog-fixedSize, .dialog-fullscreen-lowres { position: fixed !important; top: 0 !important; bottom: 0 !important; left: 0 !important; right: 0 !important; margin: 0 !important; - -webkit-box-shadow: none; - box-shadow: none + box-shadow: none; } } -@media all and (min-width:80em) and (min-height:45em) { +@media all and (min-width: 80em) and (min-height: 45em) { + .dialog-medium { width: 80%; - height: 80% + height: 80%; } .dialog-medium-tall { width: 80%; - height: 90% + height: 90%; } .dialog-small { width: 60%; - height: 80% + height: 80%; } .dialog-fullscreen-border { width: 90%; - height: 90% + height: 90%; } } .noScroll { overflow-x: hidden !important; - overflow-y: hidden !important + overflow-y: hidden !important; } .dialogBackdrop { @@ -256,12 +164,10 @@ all and (max-height:45em) { right: 0 !important; margin: 0 !important; z-index: 999999 !important; - -webkit-transition: opacity ease-out .2s; - -o-transition: opacity ease-out .2s; - transition: opacity ease-out .2s; - will-change: opacity + transition: opacity ease-out 0.2s; + will-change: opacity; } .dialogBackdropOpened { - opacity: .5 -} \ No newline at end of file + opacity: .5; +} diff --git a/src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.js b/src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.js index 9c5f6b0064..48aa006215 100644 --- a/src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.js +++ b/src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.js @@ -1,225 +1,486 @@ -define(["appRouter", "focusManager", "browser", "layoutManager", "inputManager", "dom", "css!./dialoghelper.css", "scrollStyles"], function(appRouter, focusManager, browser, layoutManager, inputManager, dom) { - "use strict"; +define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', 'dom', 'css!./dialoghelper.css', 'scrollStyles'], function (appRouter, focusManager, browser, layoutManager, inputManager, dom) { + 'use strict'; + + var globalOnOpenCallback; function enableAnimation() { - return !browser.tv && browser.supportsCssAnimation() + + // too slow + if (browser.tv) { + return false; + } + + return browser.supportsCssAnimation(); } function removeCenterFocus(dlg) { - layoutManager.tv && (dlg.classList.contains("scrollX") ? centerFocus(dlg, !0, !1) : dlg.classList.contains("smoothScrollY") && centerFocus(dlg, !1, !1)) + + if (layoutManager.tv) { + if (dlg.classList.contains('scrollX')) { + centerFocus(dlg, true, false); + } + else if (dlg.classList.contains('smoothScrollY')) { + centerFocus(dlg, false, false); + } + } } function tryRemoveElement(elem) { var parentNode = elem.parentNode; - if (parentNode) try { - parentNode.removeChild(elem) - } catch (err) { - console.log("Error removing dialog element: " + err) + if (parentNode) { + + // Seeing crashes in edge webview + try { + parentNode.removeChild(elem); + } catch (err) { + console.log('Error removing dialog element: ' + err); + } } } function DialogHashHandler(dlg, hash, resolve) { + + var self = this; + self.originalUrl = window.location.href; + var activeElement = document.activeElement; + var removeScrollLockOnClose = false; + function onHashChange(e) { + var isBack = self.originalUrl === window.location.href; - !isBack && isOpened(dlg) || window.removeEventListener("popstate", onHashChange), isBack && (self.closedByBack = !0, closeDialog(dlg)) + + if (isBack || !isOpened(dlg)) { + window.removeEventListener('popstate', onHashChange); + } + + if (isBack) { + self.closedByBack = true; + closeDialog(dlg); + } } function onBackCommand(e) { - "back" === e.detail.command && (self.closedByBack = !0, e.preventDefault(), e.stopPropagation(), closeDialog(dlg)) + + if (e.detail.command === 'back') { + self.closedByBack = true; + e.preventDefault(); + e.stopPropagation(); + closeDialog(dlg); + } } function onDialogClosed() { - if (isHistoryEnabled(dlg) || inputManager.off(dlg, onBackCommand), window.removeEventListener("popstate", onHashChange), removeBackdrop(dlg), dlg.classList.remove("opened"), removeScrollLockOnClose && document.body.classList.remove("noScroll"), !self.closedByBack && isHistoryEnabled(dlg)) { - (history.state || {}).dialogId === hash && history.back() + + if (!isHistoryEnabled(dlg)) { + inputManager.off(dlg, onBackCommand); } - if (layoutManager.tv && focusManager.focus(activeElement), "false" !== dlg.getAttribute("data-removeonclose")) { + + window.removeEventListener('popstate', onHashChange); + + removeBackdrop(dlg); + dlg.classList.remove('opened'); + + if (removeScrollLockOnClose) { + document.body.classList.remove('noScroll'); + } + + if (!self.closedByBack && isHistoryEnabled(dlg)) { + var state = history.state || {}; + if (state.dialogId === hash) { + history.back(); + } + } + + if (layoutManager.tv) { + focusManager.focus(activeElement); + } + + if (dlg.getAttribute('data-removeonclose') !== 'false') { removeCenterFocus(dlg); + var dialogContainer = dlg.dialogContainer; - dialogContainer ? (tryRemoveElement(dialogContainer), dlg.dialogContainer = null) : tryRemoveElement(dlg) + if (dialogContainer) { + tryRemoveElement(dialogContainer); + dlg.dialogContainer = null; + } else { + tryRemoveElement(dlg); + } } - setTimeout(function() { + + //resolve(); + // if we just called history.back(), then use a timeout to allow the history events to fire first + setTimeout(function () { resolve({ element: dlg, closedByBack: self.closedByBack - }) - }, 1) + }); + }, 1); + } + + dlg.addEventListener('close', onDialogClosed); + + var center = !dlg.classList.contains('dialog-fixedSize'); + if (center) { + dlg.classList.add('centeredDialog'); + } + + dlg.classList.remove('hide'); + + addBackdropOverlay(dlg); + + dlg.classList.add('opened'); + dlg.dispatchEvent(new CustomEvent('open', { + bubbles: false, + cancelable: false + })); + + if (dlg.getAttribute('data-lockscroll') === 'true' && !document.body.classList.contains('noScroll')) { + document.body.classList.add('noScroll'); + removeScrollLockOnClose = true; + } + + animateDialogOpen(dlg); + + if (isHistoryEnabled(dlg)) { + appRouter.pushState({ dialogId: hash }, "Dialog", '#' + hash); + + window.addEventListener('popstate', onHashChange); + } else { + inputManager.on(dlg, onBackCommand); } - var self = this; - self.originalUrl = window.location.href; - var activeElement = document.activeElement, - removeScrollLockOnClose = !1; - dlg.addEventListener("close", onDialogClosed), !dlg.classList.contains("dialog-fixedSize") && dlg.classList.add("centeredDialog"), dlg.classList.remove("hide"), addBackdropOverlay(dlg), dlg.classList.add("opened"), dlg.dispatchEvent(new CustomEvent("open", { - bubbles: !1, - cancelable: !1 - })), "true" !== dlg.getAttribute("data-lockscroll") || document.body.classList.contains("noScroll") || (document.body.classList.add("noScroll"), removeScrollLockOnClose = !0), animateDialogOpen(dlg), isHistoryEnabled(dlg) ? (appRouter.pushState({ - dialogId: hash - }, "Dialog", "#" + hash), window.addEventListener("popstate", onHashChange)) : inputManager.on(dlg, onBackCommand) } function addBackdropOverlay(dlg) { - var backdrop = document.createElement("div"); - backdrop.classList.add("dialogBackdrop"); + + var backdrop = document.createElement('div'); + backdrop.classList.add('dialogBackdrop'); + var backdropParent = dlg.dialogContainer || dlg; - backdropParent.parentNode.insertBefore(backdrop, backdropParent), dlg.backdrop = backdrop, backdrop.offsetWidth, backdrop.classList.add("dialogBackdropOpened"), dom.addEventListener(dlg.dialogContainer || backdrop, "click", function(e) { - e.target === dlg.dialogContainer && close(dlg) + backdropParent.parentNode.insertBefore(backdrop, backdropParent); + dlg.backdrop = backdrop; + + // trigger reflow or the backdrop will not animate + void backdrop.offsetWidth; + backdrop.classList.add('dialogBackdropOpened'); + + dom.addEventListener((dlg.dialogContainer || backdrop), 'click', function (e) { + if (e.target === dlg.dialogContainer) { + close(dlg); + } }, { - passive: !0 - }) + passive: true + }); } function isHistoryEnabled(dlg) { - return "true" === dlg.getAttribute("data-history") + return dlg.getAttribute('data-history') === 'true'; } function open(dlg) { - globalOnOpenCallback && globalOnOpenCallback(dlg); + + if (globalOnOpenCallback) { + globalOnOpenCallback(dlg); + } + var parent = dlg.parentNode; - parent && parent.removeChild(dlg); - var dialogContainer = document.createElement("div"); - return dialogContainer.classList.add("dialogContainer"), dialogContainer.appendChild(dlg), dlg.dialogContainer = dialogContainer, document.body.appendChild(dialogContainer), new Promise(function(resolve, reject) { - new DialogHashHandler(dlg, "dlg" + (new Date).getTime(), resolve) - }) + if (parent) { + parent.removeChild(dlg); + } + + var dialogContainer = document.createElement('div'); + dialogContainer.classList.add('dialogContainer'); + dialogContainer.appendChild(dlg); + dlg.dialogContainer = dialogContainer; + document.body.appendChild(dialogContainer); + + return new Promise(function (resolve, reject) { + + new DialogHashHandler(dlg, 'dlg' + new Date().getTime(), resolve); + }); } function isOpened(dlg) { - return !dlg.classList.contains("hide") + + //return dlg.opened; + return !dlg.classList.contains('hide'); } function close(dlg) { - isOpened(dlg) && (isHistoryEnabled(dlg) ? history.back() : closeDialog(dlg)) + + if (isOpened(dlg)) { + if (isHistoryEnabled(dlg)) { + history.back(); + } else { + closeDialog(dlg); + } + } } function closeDialog(dlg) { - if (!dlg.classList.contains("hide")) { - dlg.dispatchEvent(new CustomEvent("closing", { - bubbles: !1, - cancelable: !1 + + if (!dlg.classList.contains('hide')) { + + dlg.dispatchEvent(new CustomEvent('closing', { + bubbles: false, + cancelable: false })); - animateDialogClose(dlg, function() { - focusManager.popScope(dlg), dlg.classList.add("hide"), dlg.dispatchEvent(new CustomEvent("close", { - bubbles: !1, - cancelable: !1 - })) - }) + + var onAnimationFinish = function () { + focusManager.popScope(dlg); + + dlg.classList.add('hide'); + dlg.dispatchEvent(new CustomEvent('close', { + bubbles: false, + cancelable: false + })); + }; + + animateDialogClose(dlg, onAnimationFinish); } } function animateDialogOpen(dlg) { - var onAnimationFinish = function() { - focusManager.pushScope(dlg), "true" === dlg.getAttribute("data-autofocus") && focusManager.autoFocus(dlg) + + var onAnimationFinish = function () { + focusManager.pushScope(dlg); + if (dlg.getAttribute('data-autofocus') === 'true') { + focusManager.autoFocus(dlg); + } }; + if (enableAnimation()) { - var onFinish = function() { + + var onFinish = function () { dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, { - once: !0 - }), onAnimationFinish() + once: true + }); + onAnimationFinish(); }; - return void dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, { - once: !0 - }) + dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, { + once: true + }); + return; } - onAnimationFinish() + + onAnimationFinish(); } function animateDialogClose(dlg, onAnimationFinish) { + if (enableAnimation()) { - var animated = !0; + + var animated = true; + switch (dlg.animationConfig.exit.name) { - case "fadeout": - dlg.style.animation = "fadeout " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both"; + + case 'fadeout': + dlg.style.animation = 'fadeout ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both'; break; - case "scaledown": - dlg.style.animation = "scaledown " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both"; + case 'scaledown': + dlg.style.animation = 'scaledown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both'; break; - case "slidedown": - dlg.style.animation = "slidedown " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both"; + case 'slidedown': + dlg.style.animation = 'slidedown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both'; break; default: - animated = !1 + animated = false; + break; } - var onFinish = function() { + var onFinish = function () { dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, { - once: !0 - }), onAnimationFinish() + once: true + }); + onAnimationFinish(); }; - if (dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, { - once: !0 - }), animated) return + dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, { + once: true + }); + + if (animated) { + return; + } } - onAnimationFinish() + + onAnimationFinish(); } + var supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style; + function shouldLockDocumentScroll(options) { - return !(supportsOverscrollBehavior && (options.size || !browser.touch)) && (null != options.lockScroll ? options.lockScroll : "fullscreen" === options.size || (!!options.size || browser.touch)) + + if (supportsOverscrollBehavior && (options.size || !browser.touch)) { + return false; + } + + if (options.lockScroll != null) { + return options.lockScroll; + } + + if (options.size === 'fullscreen') { + return true; + } + + if (options.size) { + return true; + } + + return browser.touch; } function removeBackdrop(dlg) { + var backdrop = dlg.backdrop; - if (backdrop) { - dlg.backdrop = null; - var onAnimationFinish = function() { - tryRemoveElement(backdrop) - }; - if (enableAnimation()) return backdrop.classList.remove("dialogBackdropOpened"), void setTimeout(onAnimationFinish, 300); - onAnimationFinish() + + if (!backdrop) { + return; } + + dlg.backdrop = null; + + var onAnimationFinish = function () { + tryRemoveElement(backdrop); + }; + + if (enableAnimation()) { + + backdrop.classList.remove('dialogBackdropOpened'); + + // this is not firing animatonend + setTimeout(onAnimationFinish, 300); + return; + } + + onAnimationFinish(); } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function createDialog(options) { + options = options || {}; - var dlg = document.createElement("div"); - dlg.classList.add("focuscontainer"), dlg.classList.add("hide"), shouldLockDocumentScroll(options) && dlg.setAttribute("data-lockscroll", "true"), !1 !== options.enableHistory && appRouter.enableNativeHistory() && dlg.setAttribute("data-history", "true"), !1 !== options.modal && dlg.setAttribute("modal", "modal"), !1 !== options.autoFocus && dlg.setAttribute("data-autofocus", "true"); - var defaultEntryAnimation, defaultExitAnimation; - defaultEntryAnimation = "scaleup", defaultExitAnimation = "scaledown"; - var entryAnimation = options.entryAnimation || defaultEntryAnimation, - exitAnimation = options.exitAnimation || defaultExitAnimation, - entryAnimationDuration = options.entryAnimationDuration || ("fullscreen" !== options.size ? 180 : 280), - exitAnimationDuration = options.exitAnimationDuration || ("fullscreen" !== options.size ? 120 : 220); - if (dlg.animationConfig = { - entry: { - name: entryAnimation, - timing: { - duration: entryAnimationDuration, - easing: "ease-out" - } - }, - exit: { - name: exitAnimation, - timing: { - duration: exitAnimationDuration, - easing: "ease-out", - fill: "both" - } - } - }, dlg.classList.add("dialog"), options.scrollX ? (dlg.classList.add("scrollX"), dlg.classList.add("smoothScrollX"), layoutManager.tv && centerFocus(dlg, !0, !0)) : !1 !== options.scrollY && (dlg.classList.add("smoothScrollY"), layoutManager.tv && centerFocus(dlg, !1, !0)), options.removeOnClose && dlg.setAttribute("data-removeonclose", "true"), options.size && (dlg.classList.add("dialog-fixedSize"), dlg.classList.add("dialog-" + options.size)), enableAnimation()) switch (dlg.animationConfig.entry.name) { - case "fadein": - dlg.style.animation = "fadein " + entryAnimationDuration + "ms ease-out normal"; - break; - case "scaleup": - dlg.style.animation = "scaleup " + entryAnimationDuration + "ms ease-out normal both"; - break; - case "slideup": - dlg.style.animation = "slideup " + entryAnimationDuration + "ms ease-out normal"; - break; - case "slidedown": - dlg.style.animation = "slidedown " + entryAnimationDuration + "ms ease-out normal" + + // If there's no native dialog support, use a plain div + // Also not working well in samsung tizen browser, content inside not clickable + // Just go ahead and always use a plain div because we're seeing issues overlaying absoltutely positioned content over a modal dialog + var dlg = document.createElement('div'); + + dlg.classList.add('focuscontainer'); + dlg.classList.add('hide'); + + if (shouldLockDocumentScroll(options)) { + dlg.setAttribute('data-lockscroll', 'true'); } - return dlg + + if (options.enableHistory !== false && appRouter.enableNativeHistory()) { + dlg.setAttribute('data-history', 'true'); + } + + // without this safari will scroll the background instead of the dialog contents + // but not needed here since this is already on top of an existing dialog + // but skip it in IE because it's causing the entire browser to hang + // Also have to disable for firefox because it's causing select elements to not be clickable + if (options.modal !== false) { + dlg.setAttribute('modal', 'modal'); + } + + if (options.autoFocus !== false) { + dlg.setAttribute('data-autofocus', 'true'); + } + + var defaultEntryAnimation; + var defaultExitAnimation; + + defaultEntryAnimation = 'scaleup'; + defaultExitAnimation = 'scaledown'; + var entryAnimation = options.entryAnimation || defaultEntryAnimation; + var exitAnimation = options.exitAnimation || defaultExitAnimation; + + // If it's not fullscreen then lower the default animation speed to make it open really fast + var entryAnimationDuration = options.entryAnimationDuration || (options.size !== 'fullscreen' ? 180 : 280); + var exitAnimationDuration = options.exitAnimationDuration || (options.size !== 'fullscreen' ? 120 : 220); + + dlg.animationConfig = { + // scale up + 'entry': { + name: entryAnimation, + timing: { + duration: entryAnimationDuration, + easing: 'ease-out' + } + }, + // fade out + 'exit': { + name: exitAnimation, + timing: { + duration: exitAnimationDuration, + easing: 'ease-out', + fill: 'both' + } + } + }; + + dlg.classList.add('dialog'); + + if (options.scrollX) { + dlg.classList.add('scrollX'); + dlg.classList.add('smoothScrollX'); + + if (layoutManager.tv) { + centerFocus(dlg, true, true); + } + } + else if (options.scrollY !== false) { + dlg.classList.add('smoothScrollY'); + + if (layoutManager.tv) { + centerFocus(dlg, false, true); + } + } + + if (options.removeOnClose) { + dlg.setAttribute('data-removeonclose', 'true'); + } + + if (options.size) { + dlg.classList.add('dialog-fixedSize'); + dlg.classList.add('dialog-' + options.size); + } + + if (enableAnimation()) { + + switch (dlg.animationConfig.entry.name) { + + case 'fadein': + dlg.style.animation = 'fadein ' + entryAnimationDuration + 'ms ease-out normal'; + break; + case 'scaleup': + dlg.style.animation = 'scaleup ' + entryAnimationDuration + 'ms ease-out normal both'; + break; + case 'slideup': + dlg.style.animation = 'slideup ' + entryAnimationDuration + 'ms ease-out normal'; + break; + case 'slidedown': + dlg.style.animation = 'slidedown ' + entryAnimationDuration + 'ms ease-out normal'; + break; + default: + break; + } + } + + return dlg; } - var globalOnOpenCallback, supportsOverscrollBehavior = "overscroll-behavior-y" in document.body.style; + return { open: open, close: close, createDialog: createDialog, - setOnOpen: function(val) { - globalOnOpenCallback = val + setOnOpen: function (val) { + globalOnOpenCallback = val; } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/displaysettings/displaysettings.js b/src/bower_components/emby-webcomponents/displaysettings/displaysettings.js index 36158eaecc..90eaeba09e 100644 --- a/src/bower_components/emby-webcomponents/displaysettings/displaysettings.js +++ b/src/bower_components/emby-webcomponents/displaysettings/displaysettings.js @@ -1,122 +1,343 @@ -define(["require", "browser", "layoutManager", "appSettings", "pluginManager", "apphost", "focusManager", "datetime", "globalize", "loading", "connectionManager", "skinManager", "dom", "events", "emby-select", "emby-checkbox", "emby-linkbutton"], function(require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) { +define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', 'apphost', 'focusManager', 'datetime', 'globalize', 'loading', 'connectionManager', 'skinManager', 'dom', 'events', 'emby-select', 'emby-checkbox', 'emby-linkbutton'], function (require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) { "use strict"; function fillThemes(select, isDashboard) { - select.innerHTML = skinManager.getThemes().map(function(t) { + + select.innerHTML = skinManager.getThemes().map(function (t) { + var value = t.id; - return t.isDefault && !isDashboard ? value = "" : t.isDefaultServerDashboard && isDashboard && (value = ""), '" - }).join("") + + if (t.isDefault && !isDashboard) { + value = ''; + } + else if (t.isDefaultServerDashboard && isDashboard) { + value = ''; + } + + return ''; + + }).join(''); } function loadScreensavers(context, userSettings) { - var selectScreensaver = context.querySelector(".selectScreensaver"), - options = pluginManager.ofType("screensaver").map(function(plugin) { - return { - name: plugin.name, - value: plugin.id - } - }); + + var selectScreensaver = context.querySelector('.selectScreensaver'); + var options = pluginManager.ofType('screensaver').map(function (plugin) { + return { + name: plugin.name, + value: plugin.id + }; + }); + options.unshift({ - name: globalize.translate("sharedcomponents#None"), - value: "none" - }), selectScreensaver.innerHTML = options.map(function(o) { - return '" - }).join(""), selectScreensaver.value = userSettings.screensaver(), selectScreensaver.value || (selectScreensaver.value = "none") + name: globalize.translate('sharedcomponents#None'), + value: 'none' + }); + + selectScreensaver.innerHTML = options.map(function (o) { + return ''; + }).join(''); + selectScreensaver.value = userSettings.screensaver(); + + if (!selectScreensaver.value) { + // TODO: set the default instead of none + selectScreensaver.value = 'none'; + } } function loadSoundEffects(context, userSettings) { - var selectSoundEffects = context.querySelector(".selectSoundEffects"), - options = pluginManager.ofType("soundeffects").map(function(plugin) { - return { - name: plugin.name, - value: plugin.id - } - }); + + var selectSoundEffects = context.querySelector('.selectSoundEffects'); + var options = pluginManager.ofType('soundeffects').map(function (plugin) { + return { + name: plugin.name, + value: plugin.id + }; + }); + options.unshift({ - name: globalize.translate("sharedcomponents#None"), - value: "none" - }), selectSoundEffects.innerHTML = options.map(function(o) { - return '" - }).join(""), selectSoundEffects.value = userSettings.soundEffects(), selectSoundEffects.value || (selectSoundEffects.value = "none") + name: globalize.translate('sharedcomponents#None'), + value: 'none' + }); + + selectSoundEffects.innerHTML = options.map(function (o) { + return ''; + }).join(''); + selectSoundEffects.value = userSettings.soundEffects(); + + if (!selectSoundEffects.value) { + // TODO: set the default instead of none + selectSoundEffects.value = 'none'; + } } function loadSkins(context, userSettings) { - var selectSkin = context.querySelector(".selectSkin"), - options = pluginManager.ofType("skin").map(function(plugin) { - return { - name: plugin.name, - value: plugin.id - } - }); - selectSkin.innerHTML = options.map(function(o) { - return '" - }).join(""), selectSkin.value = userSettings.skin(), !selectSkin.value && options.length && (selectSkin.value = options[0].value), options.length > 1 && appHost.supports("skins") ? context.querySelector(".selectSkinContainer").classList.remove("hide") : context.querySelector(".selectSkinContainer").classList.add("hide") + + var selectSkin = context.querySelector('.selectSkin'); + + var options = pluginManager.ofType('skin').map(function (plugin) { + return { + name: plugin.name, + value: plugin.id + }; + }); + + selectSkin.innerHTML = options.map(function (o) { + return ''; + }).join(''); + selectSkin.value = userSettings.skin(); + + if (!selectSkin.value && options.length) { + selectSkin.value = options[0].value; + } + + if (options.length > 1 && appHost.supports('skins')) { + context.querySelector('.selectSkinContainer').classList.remove('hide'); + } else { + context.querySelector('.selectSkinContainer').classList.add('hide'); + } } function showOrHideMissingEpisodesField(context, user, apiClient) { - if (browser.tizen || browser.web0s) return void context.querySelector(".fldDisplayMissingEpisodes").classList.add("hide"); - context.querySelector(".fldDisplayMissingEpisodes").classList.remove("hide") + + if (browser.tizen || browser.web0s) { + context.querySelector('.fldDisplayMissingEpisodes').classList.add('hide'); + return; + } + + context.querySelector('.fldDisplayMissingEpisodes').classList.remove('hide'); } function loadForm(context, user, userSettings, apiClient) { - apiClient.getCurrentUserId(), user.Id; - user.Policy.IsAdministrator ? context.querySelector(".selectDashboardThemeContainer").classList.remove("hide") : context.querySelector(".selectDashboardThemeContainer").classList.add("hide"), appHost.supports("displaylanguage") ? context.querySelector(".languageSection").classList.remove("hide") : context.querySelector(".languageSection").classList.add("hide"), appHost.supports("displaymode") ? context.querySelector(".fldDisplayMode").classList.remove("hide") : context.querySelector(".fldDisplayMode").classList.add("hide"), appHost.supports("externallinks") ? context.querySelector(".learnHowToContributeContainer").classList.remove("hide") : context.querySelector(".learnHowToContributeContainer").classList.add("hide"), appHost.supports("runatstartup") ? context.querySelector(".fldAutorun").classList.remove("hide") : context.querySelector(".fldAutorun").classList.add("hide"), appHost.supports("soundeffects") ? context.querySelector(".fldSoundEffects").classList.remove("hide") : context.querySelector(".fldSoundEffects").classList.add("hide"), appHost.supports("screensaver") ? context.querySelector(".selectScreensaverContainer").classList.remove("hide") : context.querySelector(".selectScreensaverContainer").classList.add("hide"), datetime.supportsLocalization() ? context.querySelector(".fldDateTimeLocale").classList.remove("hide") : context.querySelector(".fldDateTimeLocale").classList.add("hide"), browser.tizen || browser.web0s ? (context.querySelector(".fldSeasonalThemes").classList.add("hide"), context.querySelector(".fldBackdrops").classList.add("hide"), context.querySelector(".fldThemeSong").classList.add("hide"), context.querySelector(".fldThemeVideo").classList.add("hide")) : (context.querySelector(".fldSeasonalThemes").classList.remove("hide"), context.querySelector(".fldBackdrops").classList.remove("hide"), context.querySelector(".fldThemeSong").classList.remove("hide"), context.querySelector(".fldThemeVideo").classList.remove("hide")), context.querySelector(".chkRunAtStartup").checked = appSettings.runAtStartup(); - var selectTheme = context.querySelector("#selectTheme"), - selectDashboardTheme = context.querySelector("#selectDashboardTheme"); - fillThemes(selectTheme), fillThemes(selectDashboardTheme, !0), loadScreensavers(context, userSettings), loadSoundEffects(context, userSettings), loadSkins(context, userSettings), context.querySelector(".chkDisplayMissingEpisodes").checked = user.Configuration.DisplayMissingEpisodes || !1, context.querySelector("#chkThemeSong").checked = userSettings.enableThemeSongs(), context.querySelector("#chkThemeVideo").checked = userSettings.enableThemeVideos(), context.querySelector("#chkBackdrops").checked = userSettings.enableBackdrops(), context.querySelector("#chkSeasonalThemes").checked = userSettings.enableSeasonalThemes(), context.querySelector("#selectLanguage").value = userSettings.language() || "", context.querySelector(".selectDateTimeLocale").value = userSettings.dateTimeLocale() || "", selectDashboardTheme.value = userSettings.dashboardTheme() || "", selectTheme.value = userSettings.theme() || "", context.querySelector(".selectLayout").value = layoutManager.getSavedLayout() || "", showOrHideMissingEpisodesField(context, user, apiClient), loading.hide() + + var loggedInUserId = apiClient.getCurrentUserId(); + var userId = user.Id; + + if (user.Policy.IsAdministrator) { + context.querySelector('.selectDashboardThemeContainer').classList.remove('hide'); + } else { + context.querySelector('.selectDashboardThemeContainer').classList.add('hide'); + } + + if (appHost.supports('displaylanguage')) { + context.querySelector('.languageSection').classList.remove('hide'); + } else { + context.querySelector('.languageSection').classList.add('hide'); + } + + if (appHost.supports('displaymode')) { + context.querySelector('.fldDisplayMode').classList.remove('hide'); + } else { + context.querySelector('.fldDisplayMode').classList.add('hide'); + } + + if (appHost.supports('externallinks')) { + context.querySelector('.learnHowToContributeContainer').classList.remove('hide'); + } else { + context.querySelector('.learnHowToContributeContainer').classList.add('hide'); + } + + if (appHost.supports('runatstartup')) { + context.querySelector('.fldAutorun').classList.remove('hide'); + } else { + context.querySelector('.fldAutorun').classList.add('hide'); + } + + if (appHost.supports('soundeffects')) { + context.querySelector('.fldSoundEffects').classList.remove('hide'); + } else { + context.querySelector('.fldSoundEffects').classList.add('hide'); + } + + if (appHost.supports('screensaver')) { + context.querySelector('.selectScreensaverContainer').classList.remove('hide'); + } else { + context.querySelector('.selectScreensaverContainer').classList.add('hide'); + } + + if (datetime.supportsLocalization()) { + context.querySelector('.fldDateTimeLocale').classList.remove('hide'); + } else { + context.querySelector('.fldDateTimeLocale').classList.add('hide'); + } + + if (!browser.tizen && !browser.web0s) { + context.querySelector('.fldSeasonalThemes').classList.remove('hide'); + context.querySelector('.fldBackdrops').classList.remove('hide'); + context.querySelector('.fldThemeSong').classList.remove('hide'); + context.querySelector('.fldThemeVideo').classList.remove('hide'); + } else { + context.querySelector('.fldSeasonalThemes').classList.add('hide'); + context.querySelector('.fldBackdrops').classList.add('hide'); + context.querySelector('.fldThemeSong').classList.add('hide'); + context.querySelector('.fldThemeVideo').classList.add('hide'); + } + + context.querySelector('.chkRunAtStartup').checked = appSettings.runAtStartup(); + + var selectTheme = context.querySelector('#selectTheme'); + var selectDashboardTheme = context.querySelector('#selectDashboardTheme'); + + fillThemes(selectTheme); + fillThemes(selectDashboardTheme, true); + loadScreensavers(context, userSettings); + loadSoundEffects(context, userSettings); + loadSkins(context, userSettings); + + context.querySelector('.chkDisplayMissingEpisodes').checked = user.Configuration.DisplayMissingEpisodes || false; + + context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs(); + context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos(); + context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops(); + context.querySelector('#chkSeasonalThemes').checked = userSettings.enableSeasonalThemes(); + + context.querySelector('#selectLanguage').value = userSettings.language() || ''; + context.querySelector('.selectDateTimeLocale').value = userSettings.dateTimeLocale() || ''; + + selectDashboardTheme.value = userSettings.dashboardTheme() || ''; + selectTheme.value = userSettings.theme() || ''; + + context.querySelector('.selectLayout').value = layoutManager.getSavedLayout() || ''; + + showOrHideMissingEpisodesField(context, user, apiClient); + + loading.hide(); } function saveUser(context, user, userSettingsInstance, apiClient) { - return appSettings.runAtStartup(context.querySelector(".chkRunAtStartup").checked), user.Configuration.DisplayMissingEpisodes = context.querySelector(".chkDisplayMissingEpisodes").checked, appHost.supports("displaylanguage") && userSettingsInstance.language(context.querySelector("#selectLanguage").value), userSettingsInstance.dateTimeLocale(context.querySelector(".selectDateTimeLocale").value), userSettingsInstance.enableThemeSongs(context.querySelector("#chkThemeSong").checked), userSettingsInstance.enableThemeVideos(context.querySelector("#chkThemeVideo").checked), userSettingsInstance.dashboardTheme(context.querySelector("#selectDashboardTheme").value), userSettingsInstance.theme(context.querySelector("#selectTheme").value), userSettingsInstance.soundEffects(context.querySelector(".selectSoundEffects").value), userSettingsInstance.screensaver(context.querySelector(".selectScreensaver").value), userSettingsInstance.skin(context.querySelector(".selectSkin").value), userSettingsInstance.enableBackdrops(context.querySelector("#chkBackdrops").checked), userSettingsInstance.enableSeasonalThemes(context.querySelector("#chkSeasonalThemes").checked), user.Id === apiClient.getCurrentUserId() && skinManager.setTheme(userSettingsInstance.theme()), layoutManager.setLayout(context.querySelector(".selectLayout").value), apiClient.updateUserConfiguration(user.Id, user.Configuration) + + appSettings.runAtStartup(context.querySelector('.chkRunAtStartup').checked); + + user.Configuration.DisplayMissingEpisodes = context.querySelector('.chkDisplayMissingEpisodes').checked; + + if (appHost.supports('displaylanguage')) { + userSettingsInstance.language(context.querySelector('#selectLanguage').value); + } + + userSettingsInstance.dateTimeLocale(context.querySelector('.selectDateTimeLocale').value); + + userSettingsInstance.enableThemeSongs(context.querySelector('#chkThemeSong').checked); + userSettingsInstance.enableThemeVideos(context.querySelector('#chkThemeVideo').checked); + userSettingsInstance.dashboardTheme(context.querySelector('#selectDashboardTheme').value); + userSettingsInstance.theme(context.querySelector('#selectTheme').value); + userSettingsInstance.soundEffects(context.querySelector('.selectSoundEffects').value); + userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value); + + userSettingsInstance.skin(context.querySelector('.selectSkin').value); + + userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked); + userSettingsInstance.enableSeasonalThemes(context.querySelector('#chkSeasonalThemes').checked); + + if (user.Id === apiClient.getCurrentUserId()) { + + skinManager.setTheme(userSettingsInstance.theme()); + } + + layoutManager.setLayout(context.querySelector('.selectLayout').value); + + return apiClient.updateUserConfiguration(user.Id, user.Configuration); } function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) { - loading.show(), apiClient.getUser(userId).then(function(user) { - saveUser(context, user, userSettings, apiClient).then(function() { - loading.hide(), enableSaveConfirmation && require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#SettingsSaved")) - }), events.trigger(instance, "saved") - }, function() { - loading.hide() - }) - }) + + loading.show(); + + apiClient.getUser(userId).then(function (user) { + + saveUser(context, user, userSettings, apiClient).then(function () { + + loading.hide(); + if (enableSaveConfirmation) { + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#SettingsSaved')); + }); + } + + events.trigger(instance, 'saved'); + + }, function () { + loading.hide(); + }); + }); } function onSubmit(e) { - var self = this, - apiClient = connectionManager.getApiClient(self.options.serverId), - userId = self.options.userId, - userSettings = self.options.userSettings; - return userSettings.setUserInfo(userId, apiClient).then(function() { + + var self = this; + var apiClient = connectionManager.getApiClient(self.options.serverId); + var userId = self.options.userId; + var userSettings = self.options.userSettings; + + userSettings.setUserInfo(userId, apiClient).then(function () { + var enableSaveConfirmation = self.options.enableSaveConfirmation; - save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation) - }), e && e.preventDefault(), !1 + save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation); + }); + + // Disable default form submission + if (e) { + e.preventDefault(); + } + return false; } function embed(options, self) { - require(["text!./displaysettings.template.html"], function(template) { - options.element.innerHTML = globalize.translateDocument(template, "sharedcomponents"), options.element.querySelector("form").addEventListener("submit", onSubmit.bind(self)), options.enableSaveButton && options.element.querySelector(".btnSave").classList.remove("hide"), self.loadData(options.autoFocus) - }) + + require(['text!./displaysettings.template.html'], function (template) { + + options.element.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self)); + + if (options.enableSaveButton) { + options.element.querySelector('.btnSave').classList.remove('hide'); + } + + self.loadData(options.autoFocus); + }); } function DisplaySettings(options) { - this.options = options, embed(options, this) + + this.options = options; + + embed(options, this); } - return DisplaySettings.prototype.loadData = function(autoFocus) { - var self = this, - context = self.options.element; + + DisplaySettings.prototype.loadData = function (autoFocus) { + + var self = this; + var context = self.options.element; + loading.show(); - var userId = self.options.userId, - apiClient = connectionManager.getApiClient(self.options.serverId), - userSettings = self.options.userSettings; - return apiClient.getUser(userId).then(function(user) { - return userSettings.setUserInfo(userId, apiClient).then(function() { - self.dataLoaded = !0, loadForm(context, user, userSettings, apiClient), autoFocus && focusManager.autoFocus(context) - }) - }) - }, DisplaySettings.prototype.submit = function() { - onSubmit.call(this) - }, DisplaySettings.prototype.destroy = function() { - this.options = null - }, DisplaySettings + + var userId = self.options.userId; + var apiClient = connectionManager.getApiClient(self.options.serverId); + var userSettings = self.options.userSettings; + + return apiClient.getUser(userId).then(function (user) { + + return userSettings.setUserInfo(userId, apiClient).then(function () { + + self.dataLoaded = true; + + loadForm(context, user, userSettings, apiClient); + + if (autoFocus) { + focusManager.autoFocus(context); + } + }); + }); + }; + + DisplaySettings.prototype.submit = function () { + onSubmit.call(this); + }; + + DisplaySettings.prototype.destroy = function () { + + this.options = null; + }; + + return DisplaySettings; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/displaysettings/displaysettings.template.html b/src/bower_components/emby-webcomponents/displaysettings/displaysettings.template.html index ad82c07edb..01bd14221f 100644 --- a/src/bower_components/emby-webcomponents/displaysettings/displaysettings.template.html +++ b/src/bower_components/emby-webcomponents/displaysettings/displaysettings.template.html @@ -55,7 +55,7 @@
@@ -127,6 +127,7 @@
+
${FeatureRequiresEmbyPremiere}
@@ -139,6 +140,7 @@
+
${FeatureRequiresEmbyPremiere}
@@ -188,4 +190,4 @@ - + \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/dom.js b/src/bower_components/emby-webcomponents/dom.js index cbc85e28a4..ea8902b98e 100644 --- a/src/bower_components/emby-webcomponents/dom.js +++ b/src/bower_components/emby-webcomponents/dom.js @@ -1,96 +1,170 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; function parentWithAttribute(elem, name, value) { - for (; value ? elem.getAttribute(name) !== value : !elem.getAttribute(name);) - if (!(elem = elem.parentNode) || !elem.getAttribute) return null; - return elem + + while ((value ? elem.getAttribute(name) !== value : !elem.getAttribute(name))) { + elem = elem.parentNode; + + if (!elem || !elem.getAttribute) { + return null; + } + } + + return elem; } function parentWithTag(elem, tagNames) { - for (Array.isArray(tagNames) || (tagNames = [tagNames]); - 1 === tagNames.indexOf(elem.tagName || "");) - if (!(elem = elem.parentNode)) return null; - return elem + + // accept both string and array passed in + if (!Array.isArray(tagNames)) { + tagNames = [tagNames]; + } + + while (tagNames.indexOf(elem.tagName || '') === -1) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; } function containsAnyClass(classList, classNames) { - for (var i = 0, length = classNames.length; i < length; i++) - if (classList.contains(classNames[i])) return !0; - return !1 + + for (var i = 0, length = classNames.length; i < length; i++) { + if (classList.contains(classNames[i])) { + return true; + } + } + return false; } function parentWithClass(elem, classNames) { - for (Array.isArray(classNames) || (classNames = [classNames]); !elem.classList || !containsAnyClass(elem.classList, classNames);) - if (!(elem = elem.parentNode)) return null; - return elem + + // accept both string and array passed in + if (!Array.isArray(classNames)) { + classNames = [classNames]; + } + + while (!elem.classList || !containsAnyClass(elem.classList, classNames)) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; } + var supportsCaptureOption = false; + try { + var opts = Object.defineProperty({}, 'capture', { + get: function () { + supportsCaptureOption = true; + } + }); + window.addEventListener("test", null, opts); + } catch (e) { } + function addEventListenerWithOptions(target, type, handler, options) { var optionsOrCapture = options; - supportsCaptureOption || (optionsOrCapture = options.capture), target.addEventListener(type, handler, optionsOrCapture) + if (!supportsCaptureOption) { + optionsOrCapture = options.capture; + } + target.addEventListener(type, handler, optionsOrCapture); } function removeEventListenerWithOptions(target, type, handler, options) { var optionsOrCapture = options; - supportsCaptureOption || (optionsOrCapture = options.capture), target.removeEventListener(type, handler, optionsOrCapture) + if (!supportsCaptureOption) { + optionsOrCapture = options.capture; + } + target.removeEventListener(type, handler, optionsOrCapture); } + var windowSize; + var windowSizeEventsBound; function clearWindowSize() { - windowSize = null + windowSize = null; } function getWindowSize() { - return windowSize || (windowSize = { - innerHeight: window.innerHeight, - innerWidth: window.innerWidth - }, windowSizeEventsBound || (windowSizeEventsBound = !0, addEventListenerWithOptions(window, "orientationchange", clearWindowSize, { - passive: !0 - }), addEventListenerWithOptions(window, "resize", clearWindowSize, { - passive: !0 - }))), windowSize + if (!windowSize) { + windowSize = { + innerHeight: window.innerHeight, + innerWidth: window.innerWidth + }; + + if (!windowSizeEventsBound) { + windowSizeEventsBound = true; + addEventListenerWithOptions(window, "orientationchange", clearWindowSize, { passive: true }); + addEventListenerWithOptions(window, 'resize', clearWindowSize, { passive: true }); + } + } + + return windowSize; } + var _animationEvent; function whichAnimationEvent() { - if (_animationEvent) return _animationEvent; - var t, el = document.createElement("div"), - animations = { - animation: "animationend", - OAnimation: "oAnimationEnd", - MozAnimation: "animationend", - WebkitAnimation: "webkitAnimationEnd" - }; - for (t in animations) - if (void 0 !== el.style[t]) return _animationEvent = animations[t], animations[t]; - return _animationEvent = "animationend" + + 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; } function whichAnimationCancelEvent() { - return whichAnimationEvent().replace("animationend", "animationcancel").replace("AnimationEnd", "AnimationCancel") + + return whichAnimationEvent().replace('animationend', 'animationcancel').replace('AnimationEnd', 'AnimationCancel'); } + var _transitionEvent; function whichTransitionEvent() { - if (_transitionEvent) return _transitionEvent; - var t, el = document.createElement("div"), - transitions = { - transition: "transitionend", - OTransition: "oTransitionEnd", - MozTransition: "transitionend", - WebkitTransition: "webkitTransitionEnd" - }; - for (t in transitions) - if (void 0 !== el.style[t]) return _transitionEvent = transitions[t], transitions[t]; - return _transitionEvent = "transitionend" - } - var supportsCaptureOption = !1; - try { - var opts = Object.defineProperty({}, "capture", { - get: function() { - supportsCaptureOption = !0 + 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]; } - }); - window.addEventListener("test", null, opts) - } catch (e) {} - var windowSize, windowSizeEventsBound, _animationEvent, _transitionEvent; + } + + _transitionEvent = 'transitionend'; + return _transitionEvent; + } + return { parentWithAttribute: parentWithAttribute, parentWithClass: parentWithClass, @@ -101,5 +175,5 @@ define([], function() { whichTransitionEvent: whichTransitionEvent, whichAnimationEvent: whichAnimationEvent, whichAnimationCancelEvent: whichAnimationCancelEvent - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-button/emby-button.css b/src/bower_components/emby-webcomponents/emby-button/emby-button.css index 2147405eff..90807d2a8b 100644 --- a/src/bower_components/emby-webcomponents/emby-button/emby-button.css +++ b/src/bower_components/emby-webcomponents/emby-button/emby-button.css @@ -1,33 +1,14 @@ -.emby-button, -.fab { - -webkit-box-sizing: border-box; - -webkit-box-align: center -} - -.button-flat, -.button-link { - background: 0 0 -} - -.emby-button, -.paper-icon-button-light { - text-align: center; - font-family: inherit; - color: inherit; - outline: 0 !important; - -webkit-tap-highlight-color: transparent; - position: relative -} - .emby-button { - display: -webkit-inline-box; - display: -webkit-inline-flex; + position: relative; display: inline-flex; - -webkit-align-items: center; align-items: center; box-sizing: border-box; margin: 0 .29em; + text-align: center; font-size: inherit; + font-family: inherit; + color: inherit; + outline-width: 0; -moz-user-select: none; -ms-user-select: none; -webkit-user-select: none; @@ -35,99 +16,98 @@ cursor: pointer; z-index: 0; padding: .86em 1em; + vertical-align: middle; border: 0; vertical-align: middle; - -webkit-border-radius: .2em; border-radius: .2em; + /* These are getting an outline in opera tv browsers, which run chrome 30 */ + outline: none !important; + position: relative; font-weight: 600; + /* Disable webkit tap highlighting */ + -webkit-tap-highlight-color: rgba(0,0,0,0); text-decoration: none; - line-height: 1.35 + + /* Not crazy about this but it normalizes heights between anchors and buttons */ + line-height: 1.35; } .emby-button::-moz-focus-inner { - border: 0 + border: 0; } -.button-flat:hover { - opacity: .5 +.button-flat { + background: transparent; } + .button-flat:hover { + opacity: .5; + } + .button-link { + background: transparent; margin: 0; padding: 0; - vertical-align: initial + vertical-align: initial; } .button-link-inline { - display: inline + display: inline; } .button-link:hover { - text-decoration: underline + text-decoration: underline; } .emby-button-focusscale { - -webkit-transition: -webkit-transform 180ms ease-out !important; - -o-transition: transform 180ms ease-out !important; transition: transform 180ms ease-out !important; -webkit-transform-origin: center center; - transform-origin: center center + transform-origin: center center; } -.emby-button-focusscale:focus { - -webkit-transform: scale(1.16); - transform: scale(1.16); - z-index: 1 + .emby-button-focusscale:focus { + transform: scale(1.16); + z-index: 1; + } + +.emby-button > i { + /* For non-fab buttons that have icons */ + font-size: 1.36em; } -.emby-button>i { - font-size: 1.36em -} - -.button-link>i { - font-size: 1em +.button-link > i { + font-size: 1em; } .fab { - display: -webkit-inline-box; - display: -webkit-inline-flex; display: inline-flex; - -webkit-border-radius: 50%; border-radius: 50%; padding: .6em; box-sizing: border-box; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; - text-align: center + text-align: center; } .emby-button.block { display: block; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; margin: .25em 0; - width: 100% + width: 100%; } .paper-icon-button-light { - display: -webkit-inline-box; - display: -webkit-inline-flex; + position: relative; display: inline-flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-sizing: border-box; box-sizing: border-box; margin: 0 .29em; - background: 0 0; + background: transparent; + text-align: center; font-size: inherit; + font-family: inherit; + color: inherit; -moz-user-select: none; -ms-user-select: none; -webkit-user-select: none; @@ -139,84 +119,82 @@ width: auto; height: auto; padding: .556em; + vertical-align: middle; border: 0; vertical-align: middle; + /* These are getting an outline in opera tv browsers, which run chrome 30 */ + outline: none !important; + position: relative; overflow: hidden; - -webkit-border-radius: 50%; border-radius: 50%; - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center + /* Disable webkit tap highlighting */ + -webkit-tap-highlight-color: rgba(0,0,0,0); + justify-content: center; } -.paper-icon-button-light::-moz-focus-inner { - border: 0 -} + .paper-icon-button-light::-moz-focus-inner { + border: 0; + } -.paper-icon-button-light[disabled] { - opacity: .3 -} + .paper-icon-button-light[disabled] { + opacity: .3; + } -.paper-icon-button-light>i { - font-size: 1.66956521739130434em; - position: relative; - z-index: 1; - vertical-align: middle -} + .paper-icon-button-light > i { + font-size: 1.66956521739130434em; + /* Make sure its on top of the ripple */ + position: relative; + z-index: 1; + vertical-align: middle; + } -.paper-icon-button-light>img { - width: 1.72em; - max-height: 100%; - position: relative; - z-index: 1; - vertical-align: middle -} + .paper-icon-button-light > img { + width: 1.72em; + /* Can't use 100% height or it will stretch past the boundaries in safari */ + /*height: 100%;*/ + max-height: 100%; + /* Make sure its on top of the ripple */ + position: relative; + z-index: 1; + vertical-align: middle; + } .emby-button-foreground { position: relative; - z-index: 1 + z-index: 1; } .icon-button-focusscale { - -webkit-transition: -webkit-transform 180ms ease-out !important; - -o-transition: transform 180ms ease-out !important; transition: transform 180ms ease-out !important; -webkit-transform-origin: center center; - transform-origin: center center + transform-origin: center center; } -.icon-button-focusscale:focus { - -webkit-transform: scale(1.3); - transform: scale(1.3); - z-index: 1 -} + .icon-button-focusscale:focus { + transform: scale(1.3); + z-index: 1; + } .btnFilterWithBubble { - position: relative + position: relative; } .filterButtonBubble { color: #fff; position: absolute; + background: #444; top: 0; right: 0; + /* padding: .5em; */ width: 1.6em; height: 1.6em; z-index: 100000000; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; font-size: 82%; - -webkit-border-radius: 100em; border-radius: 100em; - -webkit-box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); - box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); + box-shadow: 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12), 0px 2px 4px -1px rgba(0, 0, 0, 0.2); background: #03A9F4; - font-weight: 700 -} \ No newline at end of file + font-weight: bold; +} diff --git a/src/bower_components/emby-webcomponents/emby-button/emby-button.js b/src/bower_components/emby-webcomponents/emby-button/emby-button.js index bd27515990..173d21b9bd 100644 --- a/src/bower_components/emby-webcomponents/emby-button/emby-button.js +++ b/src/bower_components/emby-webcomponents/emby-button/emby-button.js @@ -1,29 +1,99 @@ -define(["browser", "dom", "layoutManager", "shell", "appRouter", "apphost", "css!./emby-button", "registerElement"], function(browser, dom, layoutManager, shell, appRouter, appHost) { - "use strict"; +define(['browser', 'dom', 'layoutManager', 'shell', 'appRouter', 'apphost', 'css!./emby-button', 'registerElement'], function (browser, dom, layoutManager, shell, appRouter, appHost) { + 'use strict'; + + var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype); + var EmbyLinkButtonPrototype = Object.create(HTMLAnchorElement.prototype); function openPremiumInfo() { - require(["registrationServices"], function(registrationServices) { - registrationServices.showPremiereInfo() - }) + + require(['registrationServices'], function (registrationServices) { + registrationServices.showPremiereInfo(); + }); } function onAnchorClick(e) { - var href = this.getAttribute("href") || ""; - "#" !== href ? this.getAttribute("target") ? -1 === href.indexOf("emby.media/premiere") || appHost.supports("externalpremium") ? appHost.supports("targetblank") || (e.preventDefault(), shell.openUrl(href)) : (e.preventDefault(), openPremiumInfo()) : appRouter.handleAnchorClick(e) : e.preventDefault() + + var href = this.getAttribute('href') || ''; + + if (href !== '#') { + + if (this.getAttribute('target')) { + if (href.indexOf('emby.media/premiere') !== -1 && !appHost.supports('externalpremium')) { + e.preventDefault(); + openPremiumInfo(); + } + else if (!appHost.supports('targetblank')) { + e.preventDefault(); + shell.openUrl(href); + } + } else { + appRouter.handleAnchorClick(e); + } + } else { + e.preventDefault(); + } } - var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype), - EmbyLinkButtonPrototype = Object.create(HTMLAnchorElement.prototype); - return EmbyButtonPrototype.createdCallback = function() { - this.classList.contains("emby-button") || (this.classList.add("emby-button"), browser.firefox && this.classList.add("button-link-inline"), layoutManager.tv && ("false" !== this.getAttribute("data-focusscale") && this.classList.add("emby-button-focusscale"), this.classList.add("emby-button-tv"))) - }, EmbyButtonPrototype.attachedCallback = function() { - "A" === this.tagName && (dom.removeEventListener(this, "click", onAnchorClick, {}), dom.addEventListener(this, "click", onAnchorClick, {}), "true" === this.getAttribute("data-autohide") && (appHost.supports("externallinks") ? this.classList.remove("hide") : this.classList.add("hide"))) - }, EmbyButtonPrototype.detachedCallback = function() { - dom.removeEventListener(this, "click", onAnchorClick, {}) - }, EmbyLinkButtonPrototype.createdCallback = EmbyButtonPrototype.createdCallback, EmbyLinkButtonPrototype.attachedCallback = EmbyButtonPrototype.attachedCallback, document.registerElement("emby-button", { + + EmbyButtonPrototype.createdCallback = function () { + + if (this.classList.contains('emby-button')) { + return; + } + + this.classList.add('emby-button'); + + if (browser.firefox) { + // a ff hack is needed for vertical alignment + this.classList.add('button-link-inline'); + } + + if (layoutManager.tv) { + if (this.getAttribute('data-focusscale') !== 'false') { + this.classList.add('emby-button-focusscale'); + } + this.classList.add('emby-button-tv'); + } + }; + + EmbyButtonPrototype.attachedCallback = function () { + + if (this.tagName === 'A') { + + dom.removeEventListener(this, 'click', onAnchorClick, { + }); + + dom.addEventListener(this, 'click', onAnchorClick, { + }); + + if (this.getAttribute('data-autohide') === 'true') { + if (appHost.supports('externallinks')) { + this.classList.remove('hide'); + } else { + this.classList.add('hide'); + } + } + } + }; + + EmbyButtonPrototype.detachedCallback = function () { + + dom.removeEventListener(this, 'click', onAnchorClick, { + }); + }; + + EmbyLinkButtonPrototype.createdCallback = EmbyButtonPrototype.createdCallback; + EmbyLinkButtonPrototype.attachedCallback = EmbyButtonPrototype.attachedCallback; + + document.registerElement('emby-button', { prototype: EmbyButtonPrototype, - extends: "button" - }), document.registerElement("emby-linkbutton", { + extends: 'button' + }); + + document.registerElement('emby-linkbutton', { prototype: EmbyLinkButtonPrototype, - extends: "a" - }), EmbyButtonPrototype + extends: 'a' + }); + + // For extension purposes + return EmbyButtonPrototype; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-button/paper-icon-button-light.js b/src/bower_components/emby-webcomponents/emby-button/paper-icon-button-light.js index 85b377c06f..b3b5c5aee3 100644 --- a/src/bower_components/emby-webcomponents/emby-button/paper-icon-button-light.js +++ b/src/bower_components/emby-webcomponents/emby-button/paper-icon-button-light.js @@ -1,10 +1,19 @@ -define(["layoutManager", "css!./emby-button", "registerElement"], function(layoutManager) { - "use strict"; +define(['layoutManager', 'css!./emby-button', 'registerElement'], function (layoutManager) { + 'use strict'; + var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype); - EmbyButtonPrototype.createdCallback = function() { - this.classList.add("paper-icon-button-light"), layoutManager.tv && this.classList.add("icon-button-focusscale") - }, document.registerElement("paper-icon-button-light", { + + EmbyButtonPrototype.createdCallback = function () { + + this.classList.add('paper-icon-button-light'); + + if (layoutManager.tv) { + this.classList.add('icon-button-focusscale'); + } + }; + + document.registerElement('paper-icon-button-light', { prototype: EmbyButtonPrototype, - extends: "button" - }) + extends: 'button' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.css b/src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.css index 7ae2f8c973..dc12b2de82 100644 --- a/src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.css +++ b/src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.css @@ -2,45 +2,37 @@ position: relative; z-index: 1; vertical-align: middle; - display: -webkit-inline-box; - display: -webkit-inline-flex; display: inline-flex; - -webkit-box-sizing: border-box; box-sizing: border-box; width: 100%; margin: 0; - padding: 0 0 0 2.4em; - -webkit-box-align: center; - -webkit-align-items: center; + padding: 0; + padding-left: 2.4em; align-items: center; height: 2.35em; - cursor: pointer -} - -.checkboxContainer, -.checkboxListContainer { - margin-bottom: 1.8em + cursor: pointer; } .checkboxFieldDescription { - padding-left: 2.4em + padding-left: 2.4em; } .checkboxContainer { - display: -webkit-box; - display: -webkit-flex; - display: flex + margin-bottom: 1.8em; + display: flex; +} + +.checkboxListContainer { + margin-bottom: 1.8em; } .checkboxContainer-withDescription { - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - flex-direction: column + flex-direction: column; } .emby-checkbox { position: absolute; + /* This is for focusing purposes, so the focusManager doesn't skip over it */ width: 1px; height: 1px; margin: 0; @@ -50,112 +42,109 @@ -moz-appearance: none; -webkit-appearance: none; appearance: none; - border: none + border: none; } .checkboxOutline { position: absolute; top: 3px; left: 0; - -webkit-box-sizing: border-box; + display: inline-block; box-sizing: border-box; width: 1.83em; height: 1.83em; margin: 0; overflow: hidden; border: 2px solid currentcolor; - -webkit-border-radius: .14em; border-radius: .14em; z-index: 2; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center + justify-content: center; } +/* Commenting this out - set by theme */ +/*.emby-checkbox:checked + span + span + .checkboxOutline { + border-color: #52B54B; +}*/ + .emby-checkbox-focushelper { position: absolute; - top: -.915em; - left: -.915em; + top: -0.915em; + left: -0.915em; width: 3.66em; height: 3.66em; display: inline-block; - -webkit-box-sizing: border-box; box-sizing: border-box; - margin: 3px 0 0; - -webkit-border-radius: 50%; + margin: 3px 0 0 0; border-radius: 50%; - background-color: transparent + background-color: transparent; } +/* Commenting this out - set by theme */ +/*.emby-checkbox:focus + span + .emby-checkbox-focushelper { + background-color: rgba(82, 181, 75, 0.26); +}*/ + .checkboxIcon { font-size: 1.6em; - color: #fff + color: #fff; } .checkboxIcon-checked { - display: none + display: none; } -.emby-checkbox:checked+span+span+.checkboxOutline>.checkboxIcon-checked { - display: -webkit-box !important; - display: -webkit-flex !important; - display: flex !important +.emby-checkbox:checked + span + span + .checkboxOutline > .checkboxIcon-checked { + /* background-color set by theme */ + /*background-color: #52B54B;*/ + display: flex !important; } -.emby-checkbox:checked+span+span+.checkboxOutline>.checkboxIcon-unchecked { - display: none !important +.emby-checkbox:checked + span + span + .checkboxOutline > .checkboxIcon-unchecked { + /* background-color set by theme */ + display: none !important; } -.emby-checkbox:checked[disabled]+span+span+.checkboxOutline>.checkboxIcon { - background-color: rgba(0, 0, 0, .26) +.emby-checkbox:checked[disabled] + span + span + .checkboxOutline > .checkboxIcon { + background-color: rgba(0, 0, 0, 0.26); } .checkboxLabel { position: relative; - margin: 0 + margin: 0; } -.checkboxList>.emby-checkbox-label { - display: -webkit-box; - display: -webkit-flex; +.checkboxList > .emby-checkbox-label { display: flex; - margin: .5em 0 + margin: .5em 0; } .checkboxList-verticalwrap { - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-flex-wrap: wrap; - flex-wrap: wrap + flex-wrap: wrap; } -.checkboxList-verticalwrap>.emby-checkbox-label { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: inline-flex; - margin: .3em 0; - width: 12em -} + .checkboxList-verticalwrap > .emby-checkbox-label { + display: inline-flex; + margin: .3em 0 .3em 0; + width: 12em; + } .checkboxList-paperList { - padding: 1em !important + padding: 1em !important; } .checkboxListLabel { - margin-bottom: .25em + margin-bottom: .25em; } @-webkit-keyframes repaintChrome { - - from, - to { - padding: 0 + from { + padding: 0; } -} \ No newline at end of file + + to { + padding: 0; + } +} diff --git a/src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.js b/src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.js index 38649f0934..5d350612a4 100644 --- a/src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.js +++ b/src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.js @@ -1,55 +1,110 @@ -define(["browser", "dom", "css!./emby-checkbox", "registerElement"], function(browser, dom) { - "use strict"; +define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (browser, dom) { + 'use strict'; + + var EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype); function onKeyDown(e) { - if (13 === e.keyCode) return e.preventDefault(), this.checked = !this.checked, this.dispatchEvent(new CustomEvent("change", { - bubbles: !0 - })), !1 + + // Don't submit form on enter + if (e.keyCode === 13) { + e.preventDefault(); + + this.checked = !this.checked; + + this.dispatchEvent(new CustomEvent('change', { + bubbles: true + })); + + return false; + } } + var enableRefreshHack = browser.tizen || browser.orsay || browser.operaTv || browser.web0s ? true : false; + function forceRefresh(loading) { + var elem = this.parentNode; - elem.style.webkitAnimationName = "repaintChrome", elem.style.webkitAnimationDelay = !0 === loading ? "500ms" : "", elem.style.webkitAnimationDuration = "10ms", elem.style.webkitAnimationIterationCount = "1", setTimeout(function() { - elem.style.webkitAnimationName = "" - }, !0 === loading ? 520 : 20) + + elem.style.webkitAnimationName = 'repaintChrome'; + elem.style.webkitAnimationDelay = (loading === true ? '500ms' : ''); + elem.style.webkitAnimationDuration = '10ms'; + elem.style.webkitAnimationIterationCount = '1'; + + setTimeout(function () { + elem.style.webkitAnimationName = ''; + }, (loading === true ? 520 : 20)); } - var EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype), - enableRefreshHack = !!(browser.tizen || browser.orsay || browser.operaTv || browser.web0s); - EmbyCheckboxPrototype.attachedCallback = function() { - if ("true" !== this.getAttribute("data-embycheckbox")) { - this.setAttribute("data-embycheckbox", "true"), this.classList.add("emby-checkbox"); - var labelElement = this.parentNode; - labelElement.classList.add("emby-checkbox-label"); - var labelTextElement = labelElement.querySelector("span"), - outlineClass = "checkboxOutline", - customClass = this.getAttribute("data-outlineclass"); - customClass && (outlineClass += " " + customClass); - var checkedIcon = this.getAttribute("data-checkedicon") || "", - uncheckedIcon = this.getAttribute("data-uncheckedicon") || "", - checkHtml = '' + checkedIcon + "", - uncheckedHtml = '' + uncheckedIcon + ""; - labelElement.insertAdjacentHTML("beforeend", '' + checkHtml + uncheckedHtml + ""), labelTextElement.classList.add("checkboxLabel"), this.addEventListener("keydown", onKeyDown), enableRefreshHack && (forceRefresh.call(this, !0), dom.addEventListener(this, "click", forceRefresh, { - passive: !0 - }), dom.addEventListener(this, "blur", forceRefresh, { - passive: !0 - }), dom.addEventListener(this, "focus", forceRefresh, { - passive: !0 - }), dom.addEventListener(this, "change", forceRefresh, { - passive: !0 - })) + + EmbyCheckboxPrototype.attachedCallback = function () { + + if (this.getAttribute('data-embycheckbox') === 'true') { + return; } - }, EmbyCheckboxPrototype.detachedCallback = function() { - this.removeEventListener("keydown", onKeyDown), dom.removeEventListener(this, "click", forceRefresh, { - passive: !0 - }), dom.removeEventListener(this, "blur", forceRefresh, { - passive: !0 - }), dom.removeEventListener(this, "focus", forceRefresh, { - passive: !0 - }), dom.removeEventListener(this, "change", forceRefresh, { - passive: !0 - }) - }, document.registerElement("emby-checkbox", { + + this.setAttribute('data-embycheckbox', 'true'); + + this.classList.add('emby-checkbox'); + + var labelElement = this.parentNode; + labelElement.classList.add('emby-checkbox-label'); + + var labelTextElement = labelElement.querySelector('span'); + + var outlineClass = 'checkboxOutline'; + + var customClass = this.getAttribute('data-outlineclass'); + if (customClass) { + outlineClass += ' ' + customClass; + } + + var checkedIcon = this.getAttribute('data-checkedicon') || ''; + var uncheckedIcon = this.getAttribute('data-uncheckedicon') || ''; + var checkHtml = '' + checkedIcon + ''; + var uncheckedHtml = '' + uncheckedIcon + ''; + labelElement.insertAdjacentHTML('beforeend', '' + checkHtml + uncheckedHtml + ''); + + labelTextElement.classList.add('checkboxLabel'); + + this.addEventListener('keydown', onKeyDown); + + if (enableRefreshHack) { + + forceRefresh.call(this, true); + dom.addEventListener(this, 'click', forceRefresh, { + passive: true + }); + dom.addEventListener(this, 'blur', forceRefresh, { + passive: true + }); + dom.addEventListener(this, 'focus', forceRefresh, { + passive: true + }); + dom.addEventListener(this, 'change', forceRefresh, { + passive: true + }); + } + }; + + EmbyCheckboxPrototype.detachedCallback = function () { + + this.removeEventListener('keydown', onKeyDown); + + dom.removeEventListener(this, 'click', forceRefresh, { + passive: true + }); + dom.removeEventListener(this, 'blur', forceRefresh, { + passive: true + }); + dom.removeEventListener(this, 'focus', forceRefresh, { + passive: true + }); + dom.removeEventListener(this, 'change', forceRefresh, { + passive: true + }); + }; + + document.registerElement('emby-checkbox', { prototype: EmbyCheckboxPrototype, - extends: "input" - }) -}); \ No newline at end of file + extends: 'input' + }); +}); diff --git a/src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.css b/src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.css index a03a0aee72..0a982e975d 100644 --- a/src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.css +++ b/src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.css @@ -1,56 +1,44 @@ .emby-collapse { - margin: .5em 0 + margin: .5em 0; } .collapseContent { border-width: 0; - padding: 1.25em; + padding: 1.25em 1.25em; height: 0; - -webkit-transition-property: height; - -o-transition-property: height; transition-property: height; - -webkit-transition-duration: .3s; - -o-transition-duration: .3s; - transition-duration: .3s; - overflow: hidden + transition-duration: 300ms; + overflow: hidden; } .emby-collapsible-button { margin: 0; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; + text-transform: none; width: 100%; text-align: left; text-transform: none; - border-width: 0 0 .1em; + border-width: 0 0 .1em 0; border-style: solid; padding-left: .1em; - background: 0 0; - -webkit-box-shadow: none; - box-shadow: none + background: transparent; + box-shadow: none; } .emby-collapse-expandIcon { - -webkit-transform-origin: 50% 50%; transform-origin: 50% 50%; - -webkit-transition: -webkit-transform 180ms ease-out; - -o-transition: transform 180ms ease-out; transition: transform 180ms ease-out; position: absolute; right: .5em; - font-size: 1.5em + font-size: 1.5em; } .emby-collapse-expandIconExpanded { - -webkit-transform: rotate(180deg); - transform: rotate(180deg) + transform: rotate(180deg); } .emby-collapsible-title { margin: 0; - padding: 0 -} \ No newline at end of file + padding: 0; +} diff --git a/src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.js b/src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.js index 4a237a9174..198278e1d7 100644 --- a/src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.js +++ b/src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.js @@ -1,43 +1,100 @@ -define(["browser", "css!./emby-collapse", "registerElement", "emby-button"], function(browser) { - "use strict"; +define(['browser', 'css!./emby-collapse', 'registerElement', 'emby-button'], function (browser) { + 'use strict'; + + var EmbyButtonPrototype = Object.create(HTMLDivElement.prototype); function slideDownToShow(button, elem) { - elem.classList.remove("hide"), elem.classList.add("expanded"), elem.style.height = "auto"; - var height = elem.offsetHeight + "px"; - elem.style.height = "0"; - elem.offsetHeight; - elem.style.height = height, setTimeout(function() { - elem.classList.contains("expanded") ? elem.classList.remove("hide") : elem.classList.add("hide"), elem.style.height = "auto" - }, 300), button.querySelector("i").classList.add("emby-collapse-expandIconExpanded") + + elem.classList.remove('hide'); + elem.classList.add('expanded'); + elem.style.height = 'auto'; + var height = elem.offsetHeight + 'px'; + elem.style.height = '0'; + + // trigger reflow + var newHeight = elem.offsetHeight; + elem.style.height = height; + + setTimeout(function () { + if (elem.classList.contains('expanded')) { + elem.classList.remove('hide'); + } else { + elem.classList.add('hide'); + } + elem.style.height = 'auto'; + }, 300); + + var icon = button.querySelector('i'); + //icon.innerHTML = 'expand_less'; + icon.classList.add('emby-collapse-expandIconExpanded'); } function slideUpToHide(button, elem) { - elem.style.height = elem.offsetHeight + "px"; - elem.offsetHeight; - elem.classList.remove("expanded"), elem.style.height = "0", setTimeout(function() { - elem.classList.contains("expanded") ? elem.classList.remove("hide") : elem.classList.add("hide") - }, 300), button.querySelector("i").classList.remove("emby-collapse-expandIconExpanded") + + elem.style.height = elem.offsetHeight + 'px'; + // trigger reflow + var newHeight = elem.offsetHeight; + + elem.classList.remove('expanded'); + elem.style.height = '0'; + + setTimeout(function () { + if (elem.classList.contains('expanded')) { + elem.classList.remove('hide'); + } else { + elem.classList.add('hide'); + } + }, 300); + + var icon = button.querySelector('i'); + //icon.innerHTML = 'expand_more'; + icon.classList.remove('emby-collapse-expandIconExpanded'); } function onButtonClick(e) { - var button = this, - collapseContent = button.parentNode.querySelector(".collapseContent"); - collapseContent.expanded ? (collapseContent.expanded = !1, slideUpToHide(button, collapseContent)) : (collapseContent.expanded = !0, slideDownToShow(button, collapseContent)) - } - var EmbyButtonPrototype = Object.create(HTMLDivElement.prototype); - EmbyButtonPrototype.attachedCallback = function() { - if (!this.classList.contains("emby-collapse")) { - this.classList.add("emby-collapse"); - var collapseContent = this.querySelector(".collapseContent"); - collapseContent && collapseContent.classList.add("hide"); - var title = this.getAttribute("title"), - html = ''; - this.insertAdjacentHTML("afterbegin", html); - var button = this.querySelector(".emby-collapsible-button"); - button.addEventListener("click", onButtonClick), "true" === this.getAttribute("data-expanded") && onButtonClick.call(button) + + var button = this; + var collapseContent = button.parentNode.querySelector('.collapseContent'); + + if (collapseContent.expanded) { + collapseContent.expanded = false; + slideUpToHide(button, collapseContent); + } else { + collapseContent.expanded = true; + slideDownToShow(button, collapseContent); } - }, document.registerElement("emby-collapse", { + } + + EmbyButtonPrototype.attachedCallback = function () { + + if (this.classList.contains('emby-collapse')) { + return; + } + + this.classList.add('emby-collapse'); + + var collapseContent = this.querySelector('.collapseContent'); + if (collapseContent) { + collapseContent.classList.add('hide'); + } + + var title = this.getAttribute('title'); + + var html = ''; + + this.insertAdjacentHTML('afterbegin', html); + + var button = this.querySelector('.emby-collapsible-button'); + + button.addEventListener('click', onButtonClick); + + if (this.getAttribute('data-expanded') === 'true') { + onButtonClick.call(button); + } + }; + + document.registerElement('emby-collapse', { prototype: EmbyButtonPrototype, - extends: "div" - }) + extends: 'div' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-connect/connecthelper.js b/src/bower_components/emby-webcomponents/emby-connect/connecthelper.js index 50292c9f14..054070a447 100644 --- a/src/bower_components/emby-webcomponents/emby-connect/connecthelper.js +++ b/src/bower_components/emby-webcomponents/emby-connect/connecthelper.js @@ -1,106 +1,219 @@ -define(["globalize", "apphost", "loading", "alert", "emby-linkbutton"], function(globalize, appHost, loading, alert) { - "use strict"; +define(['globalize', 'apphost', 'loading', 'alert', 'emby-linkbutton'], function (globalize, appHost, loading, alert) { + 'use strict'; function resolvePromise() { - return Promise.resolve() + return Promise.resolve(); } function rejectPromise() { - return Promise.reject() + return Promise.reject(); } function showNewUserInviteMessage(result) { - if (!result.IsNewUserInvitation && !result.IsPending) return Promise.resolve(); - var message = result.IsNewUserInvitation ? globalize.translate("sharedcomponents#MessageInvitationSentToNewUser", result.GuestDisplayName) : globalize.translate("sharedcomponents#MessageInvitationSentToUser", result.GuestDisplayName); + + if (!result.IsNewUserInvitation && !result.IsPending) { + + // It was immediately approved + return Promise.resolve(); + } + + var message = result.IsNewUserInvitation ? + globalize.translate('sharedcomponents#MessageInvitationSentToNewUser', result.GuestDisplayName) : + globalize.translate('sharedcomponents#MessageInvitationSentToUser', result.GuestDisplayName); + return alert({ + text: message, - title: globalize.translate("sharedcomponents#HeaderInvitationSent") - }).then(resolvePromise, resolvePromise) + title: globalize.translate('sharedcomponents#HeaderInvitationSent') + + }).then(resolvePromise, resolvePromise); } function inviteGuest(options) { + var apiClient = options.apiClient; - return loading.show(), apiClient.ajax({ + + loading.show(); + + // Add/Update connect info + return apiClient.ajax({ + type: "POST", - url: apiClient.getUrl("Connect/Invite"), - dataType: "json", + url: apiClient.getUrl('Connect/Invite'), + dataType: 'json', data: options.guestOptions || {} - }).then(function(result) { - return loading.hide(), showNewUserInviteMessage(result) - }, function(response) { + + }).then(function (result) { + loading.hide(); + return showNewUserInviteMessage(result); + + }, function (response) { + + loading.hide(); + var statusCode = response ? response.status : 0; - return 502 === statusCode ? showConnectServerUnreachableErrorMessage().then(rejectPromise, rejectPromise) : 404 === statusCode ? alert({ - text: globalize.translate("sharedcomponents#GuestUserNotFound") - }).then(rejectPromise, rejectPromise) : (statusCode || 0) >= 500 ? alert({ - text: globalize.translate("sharedcomponents#ErrorReachingEmbyConnect") - }).then(rejectPromise, rejectPromise) : showGuestGeneralErrorMessage().then(rejectPromise, rejectPromise) - }) + + if (statusCode === 502) { + return showConnectServerUnreachableErrorMessage().then(rejectPromise, rejectPromise); + } + else if (statusCode === 404) { + // User doesn't exist + return alert({ + text: globalize.translate('sharedcomponents#GuestUserNotFound') + }).then(rejectPromise, rejectPromise); + + } else if ((statusCode || 0) >= 500) { + + // Unable to reach connect server ? + return alert({ + text: globalize.translate('sharedcomponents#ErrorReachingEmbyConnect') + }).then(rejectPromise, rejectPromise); + + } else { + + // status 400 = account not activated + + // General error + return showGuestGeneralErrorMessage().then(rejectPromise, rejectPromise); + } + }); } function showGuestGeneralErrorMessage() { + var html; - appHost.supports("externallinks") && (html = globalize.translate("sharedcomponents#ErrorAddingGuestAccount1", 'https://github.com/jellyfin/jellyfin'), html += "

" + globalize.translate("sharedcomponents#ErrorAddingGuestAccount2", "apps@emby.media")); - var text = globalize.translate("sharedcomponents#ErrorAddingGuestAccount1", "https://github.com/jellyfin/jellyfin"); - return text += "\n\n" + globalize.translate("sharedcomponents#ErrorAddingGuestAccount2", "apps@emby.media"), alert({ + + if (appHost.supports('externallinks')) { + html = globalize.translate('sharedcomponents#ErrorAddingGuestAccount1', 'https://emby.media/connect'); + html += '

' + globalize.translate('sharedcomponents#ErrorAddingGuestAccount2', 'apps@emby.media'); + } + + var text = globalize.translate('sharedcomponents#ErrorAddingGuestAccount1', 'https://emby.media/connect'); + text += '\n\n' + globalize.translate('sharedcomponents#ErrorAddingGuestAccount2', 'apps@emby.media'); + + return alert({ text: text, html: html - }) + }); } function showConnectServerUnreachableErrorMessage() { - var text = globalize.translate("sharedcomponents#ErrorConnectServerUnreachable", "https://connect.emby.media"); + + var text = globalize.translate('sharedcomponents#ErrorConnectServerUnreachable', 'https://connect.emby.media'); + return alert({ text: text - }) + }); } function showLinkUserErrorMessage(username, statusCode) { - var html, text; - return 502 === statusCode ? showConnectServerUnreachableErrorMessage() : (username ? (appHost.supports("externallinks") && (html = globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount1", 'https://github.com/jellyfin/jellyfin'), html += "

" + globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount2", "apps@emby.media")), text = globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount1", "https://github.com/jellyfin/jellyfin"), text += "\n\n" + globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount2", "apps@emby.media")) : html = text = globalize.translate("sharedcomponents#DefaultErrorMessage"), alert({ + + var html; + var text; + + if (statusCode === 502) { + return showConnectServerUnreachableErrorMessage(); + } + else if (username) { + + if (appHost.supports('externallinks')) { + html = globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount1', 'https://emby.media/connect'); + html += '

' + globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount2', 'apps@emby.media'); + } + + text = globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount1', 'https://emby.media/connect'); + text += '\n\n' + globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount2', 'apps@emby.media'); + + } else { + html = text = globalize.translate('sharedcomponents#DefaultErrorMessage'); + } + + return alert({ text: text, html: html - })) + }); } function updateUserLink(apiClient, user, newConnectUsername) { - var currentConnectUsername = user.ConnectUserName || "", - enteredConnectUsername = newConnectUsername, - linkUrl = apiClient.getUrl("Users/" + user.Id + "/Connect/Link"); - return currentConnectUsername && !enteredConnectUsername ? apiClient.ajax({ - type: "DELETE", - url: linkUrl - }).then(function() { - return alert({ - text: globalize.translate("sharedcomponents#MessageEmbyAccontRemoved"), - title: globalize.translate("sharedcomponents#HeaderEmbyAccountRemoved") - }).catch(resolvePromise) - }, function(response) { - return 502 === (response ? response.status : 0) ? showConnectServerUnreachableErrorMessage().then(rejectPromise) : alert({ - text: globalize.translate("sharedcomponents#ErrorRemovingEmbyConnectAccount") - }).then(rejectPromise) - }) : currentConnectUsername !== enteredConnectUsername ? apiClient.ajax({ - type: "POST", - url: linkUrl, - data: { - ConnectUsername: enteredConnectUsername - }, - dataType: "json" - }).then(function(result) { - var msgKey = result.IsPending ? "sharedcomponents#MessagePendingEmbyAccountAdded" : "sharedcomponents#MessageEmbyAccountAdded"; - return alert({ - text: globalize.translate(msgKey), - title: globalize.translate("sharedcomponents#HeaderEmbyAccountAdded") - }).catch(resolvePromise) - }, function(response) { - var statusCode = response ? response.status : 0; - return 502 === statusCode ? showConnectServerUnreachableErrorMessage().then(rejectPromise) : showLinkUserErrorMessage(".", statusCode).then(rejectPromise) - }) : Promise.reject() + var currentConnectUsername = user.ConnectUserName || ''; + var enteredConnectUsername = newConnectUsername; + + var linkUrl = apiClient.getUrl('Users/' + user.Id + '/Connect/Link'); + + if (currentConnectUsername && !enteredConnectUsername) { + + // Remove connect info + // Add/Update connect info + return apiClient.ajax({ + + type: "DELETE", + url: linkUrl + + }).then(function () { + + return alert({ + text: globalize.translate('sharedcomponents#MessageEmbyAccontRemoved'), + title: globalize.translate('sharedcomponents#HeaderEmbyAccountRemoved'), + + }).catch(resolvePromise); + + }, function (response) { + + var statusCode = response ? response.status : 0; + + if (statusCode === 502) { + return showConnectServerUnreachableErrorMessage().then(rejectPromise); + } + + return alert({ + text: globalize.translate('sharedcomponents#ErrorRemovingEmbyConnectAccount') + + }).then(rejectPromise); + }); + + } + else if (currentConnectUsername !== enteredConnectUsername) { + + // Add/Update connect info + return apiClient.ajax({ + type: "POST", + url: linkUrl, + data: { + ConnectUsername: enteredConnectUsername + }, + dataType: 'json' + + }).then(function (result) { + + var msgKey = result.IsPending ? 'sharedcomponents#MessagePendingEmbyAccountAdded' : 'sharedcomponents#MessageEmbyAccountAdded'; + + return alert({ + text: globalize.translate(msgKey), + title: globalize.translate('sharedcomponents#HeaderEmbyAccountAdded'), + + }).catch(resolvePromise); + + }, function (response) { + + var statusCode = response ? response.status : 0; + + if (statusCode === 502) { + return showConnectServerUnreachableErrorMessage().then(rejectPromise); + } + + return showLinkUserErrorMessage('.', statusCode).then(rejectPromise); + }); + + } else { + return Promise.reject(); + } } + return { inviteGuest: inviteGuest, updateUserLink: updateUserLink, showLinkUserErrorMessage: showLinkUserErrorMessage, showConnectServerUnreachableErrorMessage: showConnectServerUnreachableErrorMessage - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-input/emby-input.css b/src/bower_components/emby-webcomponents/emby-input/emby-input.css index 31041f0a63..d888eb570d 100644 --- a/src/bower_components/emby-webcomponents/emby-input/emby-input.css +++ b/src/bower_components/emby-webcomponents/emby-input/emby-input.css @@ -2,35 +2,39 @@ display: block; margin: 0; margin-bottom: 0 !important; + /* Remove select styling */ + /* Font size must the 16px or larger to prevent iOS page zoom on focus */ font-size: 110%; + /* General select styles: change as needed */ font-family: inherit; font-weight: inherit; padding: .4em .25em; + /* Prevent padding from causing width overflow */ -webkit-box-sizing: border-box; box-sizing: border-box; - outline: 0 !important; - -webkit-tap-highlight-color: transparent; - width: 100% + outline: none !important; + -webkit-tap-highlight-color: rgba(0,0,0,0); + width: 100%; } -.emby-input::-moz-focus-inner { - border: 0 -} + .emby-input::-moz-focus-inner { + border: 0; + } .inputContainer { - margin-bottom: 1.8em + margin-bottom: 1.8em; } .inputLabel { display: inline-block; - margin-bottom: .25em + margin-bottom: .25em; } -.emby-input+.fieldDescription { - margin-top: .25em +.emby-input + .fieldDescription { + margin-top: .25em; } .emby-input-iconbutton { -webkit-align-self: flex-end; - align-self: flex-end -} \ No newline at end of file + align-self: flex-end; +} diff --git a/src/bower_components/emby-webcomponents/emby-input/emby-input.js b/src/bower_components/emby-webcomponents/emby-input/emby-input.js index e6d6c0aeb7..9481b89225 100644 --- a/src/bower_components/emby-webcomponents/emby-input/emby-input.js +++ b/src/bower_components/emby-webcomponents/emby-input/emby-input.js @@ -1,56 +1,125 @@ -define(["layoutManager", "browser", "dom", "css!./emby-input", "registerElement"], function(layoutManager, browser, dom) { - "use strict"; +define(['layoutManager', 'browser', 'dom', 'css!./emby-input', 'registerElement'], function (layoutManager, browser, dom) { + 'use strict'; + + var EmbyInputPrototype = Object.create(HTMLInputElement.prototype); + + var inputId = 0; + var supportsFloatingLabel = false; - function onChange() { - var label = this.labelElement; - if (this.value) label.classList.remove("inputLabel-float"); - else { - supportsFloatingLabel && "date" !== this.type && "time" !== this.type && label.classList.add("inputLabel-float") - } - } - var EmbyInputPrototype = Object.create(HTMLInputElement.prototype), - inputId = 0, - supportsFloatingLabel = !1; if (Object.getOwnPropertyDescriptor && Object.defineProperty) { - var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value"); + + var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); + + // descriptor returning null in webos if (descriptor && descriptor.configurable) { var baseSetMethod = descriptor.set; - descriptor.set = function(value) { - baseSetMethod.call(this, value), this.dispatchEvent(new CustomEvent("valueset", { - bubbles: !1, - cancelable: !1 - })) - }, Object.defineProperty(HTMLInputElement.prototype, "value", descriptor), supportsFloatingLabel = !0 + descriptor.set = function (value) { + baseSetMethod.call(this, value); + + this.dispatchEvent(new CustomEvent('valueset', { + bubbles: false, + cancelable: false + })); + }; + + Object.defineProperty(HTMLInputElement.prototype, 'value', descriptor); + supportsFloatingLabel = true; } } - EmbyInputPrototype.createdCallback = function() { - if (this.id || (this.id = "embyinput" + inputId, inputId++), !this.classList.contains("emby-input")) { - this.classList.add("emby-input"); - var parentNode = this.parentNode, - document = this.ownerDocument, - label = document.createElement("label"); - label.innerHTML = this.getAttribute("label") || "", label.classList.add("inputLabel"), label.classList.add("inputLabelUnfocused"), label.htmlFor = this.id, parentNode.insertBefore(label, this), this.labelElement = label, dom.addEventListener(this, "focus", function() { - onChange.call(this), document.attachIME && document.attachIME(this), label.classList.add("inputLabelFocused"), label.classList.remove("inputLabelUnfocused") - }, { - passive: !0 - }), dom.addEventListener(this, "blur", function() { - onChange.call(this), label.classList.remove("inputLabelFocused"), label.classList.add("inputLabelUnfocused") - }, { - passive: !0 - }), dom.addEventListener(this, "change", onChange, { - passive: !0 - }), dom.addEventListener(this, "input", onChange, { - passive: !0 - }), dom.addEventListener(this, "valueset", onChange, { - passive: !0 - }), browser.orsay && this === document.activeElement && document.attachIME && document.attachIME(this) + + EmbyInputPrototype.createdCallback = function () { + + if (!this.id) { + this.id = 'embyinput' + inputId; + inputId++; + } if (this.classList.contains('emby-input')) { + return; } - }, EmbyInputPrototype.attachedCallback = function() { - this.labelElement.htmlFor = this.id, onChange.call(this) - }, EmbyInputPrototype.label = function(text) { - this.labelElement.innerHTML = text - }, document.registerElement("emby-input", { + + this.classList.add('emby-input'); + + var parentNode = this.parentNode; + var document = this.ownerDocument; + var label = document.createElement('label'); + label.innerHTML = this.getAttribute('label') || ''; + label.classList.add('inputLabel'); + label.classList.add('inputLabelUnfocused'); + + label.htmlFor = this.id; + parentNode.insertBefore(label, this); + this.labelElement = label; + + dom.addEventListener(this, 'focus', function () { + onChange.call(this); + + // For Samsung orsay devices + if (document.attachIME) { + document.attachIME(this); + } + + label.classList.add('inputLabelFocused'); + label.classList.remove('inputLabelUnfocused'); + }, { + passive: true + }); + + dom.addEventListener(this, 'blur', function () { + onChange.call(this); + label.classList.remove('inputLabelFocused'); + label.classList.add('inputLabelUnfocused'); + }, { + passive: true + }); + + dom.addEventListener(this, 'change', onChange, { + passive: true + }); + dom.addEventListener(this, 'input', onChange, { + passive: true + }); + dom.addEventListener(this, 'valueset', onChange, { + passive: true + }); + + if (browser.orsay) { + if (this === document.activeElement) { + //Make sure the IME pops up if this is the first/default element on the page + if (document.attachIME) { + document.attachIME(this); + } + } + } + + }; + + function onChange() { + + var label = this.labelElement; + if (this.value) { + label.classList.remove('inputLabel-float'); + } else { + + var instanceSupportsFloat = supportsFloatingLabel && this.type !== 'date' && this.type !== 'time'; + + if (instanceSupportsFloat) { + label.classList.add('inputLabel-float'); + } + } + } + + EmbyInputPrototype.attachedCallback = function () { + + this.labelElement.htmlFor = this.id; + + onChange.call(this); + }; + + EmbyInputPrototype.label = function (text) { + this.labelElement.innerHTML = text; + }; + + document.registerElement('emby-input', { prototype: EmbyInputPrototype, - extends: "input" - }) + extends: 'input' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-itemrefreshindicator/emby-itemrefreshindicator.js b/src/bower_components/emby-webcomponents/emby-itemrefreshindicator/emby-itemrefreshindicator.js index a575c8ec27..502af23542 100644 --- a/src/bower_components/emby-webcomponents/emby-itemrefreshindicator/emby-itemrefreshindicator.js +++ b/src/bower_components/emby-webcomponents/emby-itemrefreshindicator/emby-itemrefreshindicator.js @@ -1,32 +1,77 @@ -define(["emby-progressring", "dom", "serverNotifications", "events", "registerElement"], function(EmbyProgressRing, dom, serverNotifications, events) { - "use strict"; +define(['emby-progressring', 'dom', 'serverNotifications', 'events', 'registerElement'], function (EmbyProgressRing, dom, serverNotifications, events) { + 'use strict'; function addNotificationEvent(instance, name, handler) { + var localHandler = handler.bind(instance); - events.on(serverNotifications, name, localHandler), instance[name] = localHandler + events.on(serverNotifications, name, localHandler); + instance[name] = localHandler; } function removeNotificationEvent(instance, name) { + var handler = instance[name]; - handler && (events.off(serverNotifications, name, handler), instance[name] = null) + if (handler) { + events.off(serverNotifications, name, handler); + instance[name] = null; + } } function onRefreshProgress(e, apiClient, info) { + var indicator = this; - if (indicator.itemId || (indicator.itemId = dom.parentWithAttribute(indicator, "data-id").getAttribute("data-id")), info.ItemId === indicator.itemId) { + + if (!indicator.itemId) { + indicator.itemId = dom.parentWithAttribute(indicator, 'data-id').getAttribute('data-id'); + } + + if (info.ItemId === indicator.itemId) { + var progress = parseFloat(info.Progress); - progress && progress < 100 ? this.classList.remove("hide") : this.classList.add("hide"), this.setProgress(progress) + + if (progress && progress < 100) { + this.classList.remove('hide'); + } else { + this.classList.add('hide'); + } + + this.setProgress(progress); } } + var EmbyItemRefreshIndicatorPrototype = Object.create(EmbyProgressRing); - EmbyItemRefreshIndicatorPrototype.createdCallback = function() { - EmbyProgressRing.createdCallback && EmbyProgressRing.createdCallback.call(this), addNotificationEvent(this, "RefreshProgress", onRefreshProgress) - }, EmbyItemRefreshIndicatorPrototype.attachedCallback = function() { - EmbyProgressRing.attachedCallback && EmbyProgressRing.attachedCallback.call(this) - }, EmbyItemRefreshIndicatorPrototype.detachedCallback = function() { - EmbyProgressRing.detachedCallback && EmbyProgressRing.detachedCallback.call(this), removeNotificationEvent(this, "RefreshProgress"), this.itemId = null - }, document.registerElement("emby-itemrefreshindicator", { + + EmbyItemRefreshIndicatorPrototype.createdCallback = function () { + + // base method + if (EmbyProgressRing.createdCallback) { + EmbyProgressRing.createdCallback.call(this); + } + + addNotificationEvent(this, 'RefreshProgress', onRefreshProgress); + }; + + EmbyItemRefreshIndicatorPrototype.attachedCallback = function () { + + // base method + if (EmbyProgressRing.attachedCallback) { + EmbyProgressRing.attachedCallback.call(this); + } + }; + + EmbyItemRefreshIndicatorPrototype.detachedCallback = function () { + + // base method + if (EmbyProgressRing.detachedCallback) { + EmbyProgressRing.detachedCallback.call(this); + } + + removeNotificationEvent(this, 'RefreshProgress'); + this.itemId = null; + }; + + document.registerElement('emby-itemrefreshindicator', { prototype: EmbyItemRefreshIndicatorPrototype, - extends: "div" - }) + extends: 'div' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-itemscontainer/emby-itemscontainer.js b/src/bower_components/emby-webcomponents/emby-itemscontainer/emby-itemscontainer.js index b33c3f4509..cd2cab827b 100644 --- a/src/bower_components/emby-webcomponents/emby-itemscontainer/emby-itemscontainer.js +++ b/src/bower_components/emby-webcomponents/emby-itemscontainer/emby-itemscontainer.js @@ -1,220 +1,548 @@ -define(["itemShortcuts", "inputManager", "connectionManager", "playbackManager", "imageLoader", "layoutManager", "browser", "dom", "loading", "focusManager", "serverNotifications", "events", "registerElement"], function(itemShortcuts, inputManager, connectionManager, playbackManager, imageLoader, layoutManager, browser, dom, loading, focusManager, serverNotifications, events) { - "use strict"; +define(['itemShortcuts', 'inputManager', 'connectionManager', 'playbackManager', 'imageLoader', 'layoutManager', 'browser', 'dom', 'loading', 'focusManager', 'serverNotifications', 'events', 'registerElement'], function (itemShortcuts, inputManager, connectionManager, playbackManager, imageLoader, layoutManager, browser, dom, loading, focusManager, serverNotifications, events) { + 'use strict'; + + var ItemsContainerProtoType = Object.create(HTMLDivElement.prototype); function onClick(e) { - var itemsContainer = this, - multiSelect = (e.target, itemsContainer.multiSelect); - multiSelect && !1 === multiSelect.onContainerClick.call(itemsContainer, e) || itemShortcuts.onClick.call(itemsContainer, e) + + var itemsContainer = this; + var target = e.target; + + var multiSelect = itemsContainer.multiSelect; + + if (multiSelect) { + if (multiSelect.onContainerClick.call(itemsContainer, e) === false) { + return; + } + } + + itemShortcuts.onClick.call(itemsContainer, e); } function disableEvent(e) { - return e.preventDefault(), e.stopPropagation(), !1 + + e.preventDefault(); + e.stopPropagation(); + return false; } function onContextMenu(e) { - var target = e.target, - card = dom.parentWithAttribute(target, "data-id"); - if (card && card.getAttribute("data-serverid")) return inputManager.trigger("menu", { - sourceElement: card - }), e.preventDefault(), e.stopPropagation(), !1 + + var itemsContainer = this; + + var target = e.target; + var card = dom.parentWithAttribute(target, 'data-id'); + + // check for serverId, it won't be present on selectserver + if (card && card.getAttribute('data-serverid')) { + + inputManager.trigger('menu', { + sourceElement: card + }); + + e.preventDefault(); + e.stopPropagation(); + return false; + } } function getShortcutOptions() { return { - click: !1 - } + click: false + }; } + ItemsContainerProtoType.enableMultiSelect = function (enabled) { + + var current = this.multiSelect; + + if (!enabled) { + if (current) { + current.destroy(); + this.multiSelect = null; + } + return; + } + + if (current) { + return; + } + + var self = this; + require(['multiSelect'], function (MultiSelect) { + self.multiSelect = new MultiSelect({ + container: self, + bindOnClick: false + }); + }); + }; + function onDrop(evt, itemsContainer) { - var el = evt.item, - newIndex = evt.newIndex, - itemId = el.getAttribute("data-playlistitemid"), - playlistId = el.getAttribute("data-playlistid"); + + var el = evt.item; + + var newIndex = evt.newIndex; + var itemId = el.getAttribute('data-playlistitemid'); + var playlistId = el.getAttribute('data-playlistid'); + if (!playlistId) { + var oldIndex = evt.oldIndex; - return void el.dispatchEvent(new CustomEvent("itemdrop", { + + el.dispatchEvent(new CustomEvent('itemdrop', { detail: { oldIndex: oldIndex, newIndex: newIndex, playlistItemId: itemId }, - bubbles: !0, - cancelable: !1 - })) + bubbles: true, + cancelable: false + })); + return; } - var serverId = el.getAttribute("data-serverid"), - apiClient = connectionManager.getApiClient(serverId); - loading.show(), apiClient.ajax({ - url: apiClient.getUrl("Playlists/" + playlistId + "/Items/" + itemId + "/Move/" + newIndex), - type: "POST" - }).then(function() { - loading.hide() - }, function() { - loading.hide(), itemsContainer.refreshItems() - }) + + var serverId = el.getAttribute('data-serverid'); + var apiClient = connectionManager.getApiClient(serverId); + + loading.show(); + + apiClient.ajax({ + + url: apiClient.getUrl('Playlists/' + playlistId + '/Items/' + itemId + '/Move/' + newIndex), + + type: 'POST' + + }).then(function () { + + loading.hide(); + + }, function () { + + loading.hide(); + + itemsContainer.refreshItems(); + }); } - function onUserDataChanged(e, apiClient, userData) { - var itemsContainer = this; - require(["cardBuilder"], function(cardBuilder) { - cardBuilder.onUserDataChanged(userData, itemsContainer) + ItemsContainerProtoType.enableDragReordering = function (enabled) { + + var current = this.sortable; + + if (!enabled) { + if (current) { + current.destroy(); + this.sortable = null; + } + return; + } + + if (current) { + return; + } + + var self = this; + require(['sortable'], function (Sortable) { + + self.sortable = new Sortable(self, { + + draggable: ".listItem", + handle: '.listViewDragHandle', + + // dragging ended + onEnd: function (/**Event*/evt) { + + return onDrop(evt, self); + } + }); }); - var eventsToMonitor = getEventsToMonitor(itemsContainer); - 1 !== eventsToMonitor.indexOf("markfavorite") ? itemsContainer.notifyRefreshNeeded() : -1 !== eventsToMonitor.indexOf("markplayed") && itemsContainer.notifyRefreshNeeded() + }; + + function onUserDataChanged(e, apiClient, userData) { + + var itemsContainer = this; + + require(['cardBuilder'], function (cardBuilder) { + cardBuilder.onUserDataChanged(userData, itemsContainer); + }); + + var eventsToMonitor = getEventsToMonitor(itemsContainer); + + // TODO: Check user data change reason? + if (eventsToMonitor.indexOf('markfavorite') !== -1) { + + itemsContainer.notifyRefreshNeeded(); + } + else if (eventsToMonitor.indexOf('markplayed') !== -1) { + + itemsContainer.notifyRefreshNeeded(); + } } function getEventsToMonitor(itemsContainer) { - var monitor = itemsContainer.getAttribute("data-monitor"); - return monitor ? monitor.split(",") : [] + + var monitor = itemsContainer.getAttribute('data-monitor'); + if (monitor) { + return monitor.split(','); + } + + return []; } function onTimerCreated(e, apiClient, data) { + var itemsContainer = this; - if (-1 !== getEventsToMonitor(itemsContainer).indexOf("timers")) return void itemsContainer.notifyRefreshNeeded(); - var programId = data.ProgramId, - newTimerId = data.Id; - require(["cardBuilder"], function(cardBuilder) { - cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer) - }) + + if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) { + + itemsContainer.notifyRefreshNeeded(); + return; + } + + var programId = data.ProgramId; + // This could be null, not supported by all tv providers + var newTimerId = data.Id; + + require(['cardBuilder'], function (cardBuilder) { + cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer); + }); } function onSeriesTimerCreated(e, apiClient, data) { + var itemsContainer = this; - if (-1 !== getEventsToMonitor(itemsContainer).indexOf("seriestimers")) return void itemsContainer.notifyRefreshNeeded() + if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) { + + itemsContainer.notifyRefreshNeeded(); + return; + } } function onTimerCancelled(e, apiClient, data) { var itemsContainer = this; - if (-1 !== getEventsToMonitor(itemsContainer).indexOf("timers")) return void itemsContainer.notifyRefreshNeeded(); + + if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) { + + itemsContainer.notifyRefreshNeeded(); + return; + } + var id = data.Id; - require(["cardBuilder"], function(cardBuilder) { - cardBuilder.onTimerCancelled(id, itemsContainer) - }) + + require(['cardBuilder'], function (cardBuilder) { + cardBuilder.onTimerCancelled(id, itemsContainer); + }); } function onSeriesTimerCancelled(e, apiClient, data) { + var itemsContainer = this; - if (-1 !== getEventsToMonitor(itemsContainer).indexOf("seriestimers")) return void itemsContainer.notifyRefreshNeeded(); + if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) { + + itemsContainer.notifyRefreshNeeded(); + return; + } + var id = data.Id; - require(["cardBuilder"], function(cardBuilder) { - cardBuilder.onSeriesTimerCancelled(id, itemsContainer) - }) + + require(['cardBuilder'], function (cardBuilder) { + cardBuilder.onSeriesTimerCancelled(id, itemsContainer); + }); } function onLibraryChanged(e, apiClient, data) { - var itemsContainer = this, - eventsToMonitor = getEventsToMonitor(itemsContainer); - if (-1 === eventsToMonitor.indexOf("seriestimers") && -1 === eventsToMonitor.indexOf("timers")) { - var itemsAdded = data.ItemsAdded || [], - itemsRemoved = data.ItemsRemoved || []; - if (itemsAdded.length || itemsRemoved.length) { - var parentId = itemsContainer.getAttribute("data-parentid"); - if (parentId) { - var foldersAddedTo = data.FoldersAddedTo || [], - foldersRemovedFrom = data.FoldersRemovedFrom || [], - collectionFolders = data.CollectionFolders || []; - if (-1 === foldersAddedTo.indexOf(parentId) && -1 === foldersRemovedFrom.indexOf(parentId) && -1 === collectionFolders.indexOf(parentId)) return - } - itemsContainer.notifyRefreshNeeded() + + var itemsContainer = this; + var eventsToMonitor = getEventsToMonitor(itemsContainer); + if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) { + + // yes this is an assumption + return; + } + + var itemsAdded = data.ItemsAdded || []; + var itemsRemoved = data.ItemsRemoved || []; + if (!itemsAdded.length && !itemsRemoved.length) { + return; + } + + var parentId = itemsContainer.getAttribute('data-parentid'); + if (parentId) { + var foldersAddedTo = data.FoldersAddedTo || []; + var foldersRemovedFrom = data.FoldersRemovedFrom || []; + var collectionFolders = data.CollectionFolders || []; + + if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) { + return; + } + } + + itemsContainer.notifyRefreshNeeded(); + } + + function onPlaybackStopped(e, stopInfo) { + + var itemsContainer = this; + + var state = stopInfo.state; + + var eventsToMonitor = getEventsToMonitor(itemsContainer); + if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') { + + if (eventsToMonitor.indexOf('videoplayback') !== -1) { + + itemsContainer.notifyRefreshNeeded(true); + return; + } + } + + else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') { + + if (eventsToMonitor.indexOf('audioplayback') !== -1) { + + itemsContainer.notifyRefreshNeeded(true); + return; } } } - function onPlaybackStopped(e, stopInfo) { - var itemsContainer = this, - state = stopInfo.state, - eventsToMonitor = getEventsToMonitor(itemsContainer); - if (state.NowPlayingItem && "Video" === state.NowPlayingItem.MediaType) { - if (-1 !== eventsToMonitor.indexOf("videoplayback")) return void itemsContainer.notifyRefreshNeeded(!0) - } else if (state.NowPlayingItem && "Audio" === state.NowPlayingItem.MediaType && -1 !== eventsToMonitor.indexOf("audioplayback")) return void itemsContainer.notifyRefreshNeeded(!0) - } - function addNotificationEvent(instance, name, handler, owner) { + var localHandler = handler.bind(instance); - owner = owner || serverNotifications, events.on(owner, name, localHandler), instance["event_" + name] = localHandler + owner = owner || serverNotifications; + events.on(owner, name, localHandler); + instance['event_' + name] = localHandler; } function removeNotificationEvent(instance, name, owner) { - var handler = instance["event_" + name]; - handler && (owner = owner || serverNotifications, events.off(owner, name, handler), instance["event_" + name] = null) + + var handler = instance['event_' + name]; + if (handler) { + owner = owner || serverNotifications; + events.off(owner, name, handler); + instance['event_' + name] = null; + } } + ItemsContainerProtoType.createdCallback = function () { + + this.classList.add('itemsContainer'); + }; + + ItemsContainerProtoType.attachedCallback = function () { + + this.addEventListener('click', onClick); + + if (browser.touch) { + this.addEventListener('contextmenu', disableEvent); + } else { + if (this.getAttribute('data-contextmenu') !== 'false') { + this.addEventListener('contextmenu', onContextMenu); + } + } + + if (layoutManager.desktop || layoutManager.mobile) { + if (this.getAttribute('data-multiselect') !== 'false') { + this.enableMultiSelect(true); + } + } + + if (layoutManager.tv) { + this.classList.add('itemsContainer-tv'); + } + + itemShortcuts.on(this, getShortcutOptions()); + + addNotificationEvent(this, 'UserDataChanged', onUserDataChanged); + addNotificationEvent(this, 'TimerCreated', onTimerCreated); + addNotificationEvent(this, 'SeriesTimerCreated', onSeriesTimerCreated); + addNotificationEvent(this, 'TimerCancelled', onTimerCancelled); + addNotificationEvent(this, 'SeriesTimerCancelled', onSeriesTimerCancelled); + addNotificationEvent(this, 'LibraryChanged', onLibraryChanged); + addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager); + + if (this.getAttribute('data-dragreorder') === 'true') { + this.enableDragReordering(true); + } + }; + + ItemsContainerProtoType.detachedCallback = function () { + + clearRefreshInterval(this); + + this.enableMultiSelect(false); + this.enableDragReordering(false); + this.removeEventListener('click', onClick); + this.removeEventListener('contextmenu', onContextMenu); + this.removeEventListener('contextmenu', disableEvent); + itemShortcuts.off(this, getShortcutOptions()); + + removeNotificationEvent(this, 'UserDataChanged'); + removeNotificationEvent(this, 'TimerCreated'); + removeNotificationEvent(this, 'SeriesTimerCreated'); + removeNotificationEvent(this, 'TimerCancelled'); + removeNotificationEvent(this, 'SeriesTimerCancelled'); + removeNotificationEvent(this, 'LibraryChanged'); + removeNotificationEvent(this, 'playbackstop', playbackManager); + + this.fetchData = null; + this.getItemsHtml = null; + this.parentContainer = null; + }; + + ItemsContainerProtoType.pause = function () { + + clearRefreshInterval(this, true); + + this.paused = true; + }; + + ItemsContainerProtoType.resume = function (options) { + + this.paused = false; + + var refreshIntervalEndTime = this.refreshIntervalEndTime; + if (refreshIntervalEndTime) { + + var remainingMs = refreshIntervalEndTime - new Date().getTime(); + if (remainingMs > 0 && !this.needsRefresh) { + + resetRefreshInterval(this, remainingMs); + + } else { + this.needsRefresh = true; + this.refreshIntervalEndTime = null; + } + } + + if (this.needsRefresh || (options && options.refresh)) { + return this.refreshItems(); + } + + return Promise.resolve(); + }; + + ItemsContainerProtoType.refreshItems = function () { + + if (!this.fetchData) { + return Promise.resolve(); + } + + if (this.paused) { + this.needsRefresh = true; + return Promise.resolve(); + } + + this.needsRefresh = false; + + return this.fetchData().then(onDataFetched.bind(this)); + }; + + ItemsContainerProtoType.notifyRefreshNeeded = function (isInForeground) { + + if (this.paused) { + this.needsRefresh = true; + return; + } + + var timeout = this.refreshTimeout; + if (timeout) { + clearTimeout(timeout); + } + + if (isInForeground === true) { + this.refreshItems(); + } else { + this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000); + } + }; + function clearRefreshInterval(itemsContainer, isPausing) { - itemsContainer.refreshInterval && (clearInterval(itemsContainer.refreshInterval), itemsContainer.refreshInterval = null, isPausing || (itemsContainer.refreshIntervalEndTime = null)) + + if (itemsContainer.refreshInterval) { + + clearInterval(itemsContainer.refreshInterval); + itemsContainer.refreshInterval = null; + + if (!isPausing) { + itemsContainer.refreshIntervalEndTime = null; + } + } } function resetRefreshInterval(itemsContainer, intervalMs) { - clearRefreshInterval(itemsContainer), intervalMs || (intervalMs = parseInt(itemsContainer.getAttribute("data-refreshinterval") || "0")), intervalMs && (itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs), itemsContainer.refreshIntervalEndTime = (new Date).getTime() + intervalMs) + + clearRefreshInterval(itemsContainer); + + if (!intervalMs) { + intervalMs = parseInt(itemsContainer.getAttribute('data-refreshinterval') || '0'); + } + + if (intervalMs) { + itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs); + itemsContainer.refreshIntervalEndTime = new Date().getTime() + intervalMs; + } } function onDataFetched(result) { - var items = result.Items || result, - parentContainer = this.parentContainer; - parentContainer && (items.length ? parentContainer.classList.remove("hide") : parentContainer.classList.add("hide")); - var focusId, hasActiveElement, activeElement = document.activeElement; - this.contains(activeElement) && (hasActiveElement = !0, focusId = activeElement.getAttribute("data-id")), this.innerHTML = this.getItemsHtml(items), imageLoader.lazyChildren(this), hasActiveElement && setFocus(this, focusId), resetRefreshInterval(this), this.afterRefresh && this.afterRefresh(result) + + var items = result.Items || result; + + var parentContainer = this.parentContainer; + if (parentContainer) { + if (items.length) { + parentContainer.classList.remove('hide'); + } else { + parentContainer.classList.add('hide'); + } + } + + // Scroll back up so they can see the results from the beginning + // TODO: Find scroller + //window.scrollTo(0, 0); + + var activeElement = document.activeElement; + var focusId; + var hasActiveElement; + + if (this.contains(activeElement)) { + hasActiveElement = true; + focusId = activeElement.getAttribute('data-id'); + } + + this.innerHTML = this.getItemsHtml(items); + + imageLoader.lazyChildren(this); + + if (hasActiveElement) { + setFocus(this, focusId); + } + + resetRefreshInterval(this); + + if (this.afterRefresh) { + this.afterRefresh(result); + } } function setFocus(itemsContainer, focusId) { if (focusId) { var newElement = itemsContainer.querySelector('[data-id="' + focusId + '"]'); - if (newElement) try { - return void focusManager.focus(newElement) - } catch (err) {} + if (newElement) { + + try { + focusManager.focus(newElement); + return; + } + catch (err) { + } + } } - focusManager.autoFocus(itemsContainer) + + focusManager.autoFocus(itemsContainer); } - var ItemsContainerProtoType = Object.create(HTMLDivElement.prototype); - ItemsContainerProtoType.enableMultiSelect = function(enabled) { - var current = this.multiSelect; - if (!enabled) return void(current && (current.destroy(), this.multiSelect = null)); - if (!current) { - var self = this; - require(["multiSelect"], function(MultiSelect) { - self.multiSelect = new MultiSelect({ - container: self, - bindOnClick: !1 - }) - }) - } - }, ItemsContainerProtoType.enableDragReordering = function(enabled) { - var current = this.sortable; - if (!enabled) return void(current && (current.destroy(), this.sortable = null)); - if (!current) { - var self = this; - require(["sortable"], function(Sortable) { - self.sortable = new Sortable(self, { - draggable: ".listItem", - handle: ".listViewDragHandle", - onEnd: function(evt) { - return onDrop(evt, self) - } - }) - }) - } - }, ItemsContainerProtoType.createdCallback = function() { - this.classList.add("itemsContainer") - }, ItemsContainerProtoType.attachedCallback = function() { - this.addEventListener("click", onClick), browser.touch ? this.addEventListener("contextmenu", disableEvent) : "false" !== this.getAttribute("data-contextmenu") && this.addEventListener("contextmenu", onContextMenu), (layoutManager.desktop || layoutManager.mobile) && "false" !== this.getAttribute("data-multiselect") && this.enableMultiSelect(!0), layoutManager.tv && this.classList.add("itemsContainer-tv"), itemShortcuts.on(this, getShortcutOptions()), addNotificationEvent(this, "UserDataChanged", onUserDataChanged), addNotificationEvent(this, "TimerCreated", onTimerCreated), addNotificationEvent(this, "SeriesTimerCreated", onSeriesTimerCreated), addNotificationEvent(this, "TimerCancelled", onTimerCancelled), addNotificationEvent(this, "SeriesTimerCancelled", onSeriesTimerCancelled), addNotificationEvent(this, "LibraryChanged", onLibraryChanged), addNotificationEvent(this, "playbackstop", onPlaybackStopped, playbackManager), "true" === this.getAttribute("data-dragreorder") && this.enableDragReordering(!0) - }, ItemsContainerProtoType.detachedCallback = function() { - clearRefreshInterval(this), this.enableMultiSelect(!1), this.enableDragReordering(!1), this.removeEventListener("click", onClick), this.removeEventListener("contextmenu", onContextMenu), this.removeEventListener("contextmenu", disableEvent), itemShortcuts.off(this, getShortcutOptions()), removeNotificationEvent(this, "UserDataChanged"), removeNotificationEvent(this, "TimerCreated"), removeNotificationEvent(this, "SeriesTimerCreated"), removeNotificationEvent(this, "TimerCancelled"), removeNotificationEvent(this, "SeriesTimerCancelled"), removeNotificationEvent(this, "LibraryChanged"), removeNotificationEvent(this, "playbackstop", playbackManager), this.fetchData = null, this.getItemsHtml = null, this.parentContainer = null - }, ItemsContainerProtoType.pause = function() { - clearRefreshInterval(this, !0), this.paused = !0 - }, ItemsContainerProtoType.resume = function(options) { - this.paused = !1; - var refreshIntervalEndTime = this.refreshIntervalEndTime; - if (refreshIntervalEndTime) { - var remainingMs = refreshIntervalEndTime - (new Date).getTime(); - remainingMs > 0 && !this.needsRefresh ? resetRefreshInterval(this, remainingMs) : (this.needsRefresh = !0, this.refreshIntervalEndTime = null) - } - return this.needsRefresh || options && options.refresh ? this.refreshItems() : Promise.resolve() - }, ItemsContainerProtoType.refreshItems = function() { - return this.fetchData ? this.paused ? (this.needsRefresh = !0, Promise.resolve()) : (this.needsRefresh = !1, this.fetchData().then(onDataFetched.bind(this))) : Promise.resolve() - }, ItemsContainerProtoType.notifyRefreshNeeded = function(isInForeground) { - if (this.paused) return void(this.needsRefresh = !0); - var timeout = this.refreshTimeout; - timeout && clearTimeout(timeout), !0 === isInForeground ? this.refreshItems() : this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 1e4) - }, document.registerElement("emby-itemscontainer", { + + document.registerElement('emby-itemscontainer', { prototype: ItemsContainerProtoType, - extends: "div" - }) + extends: 'div' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.css b/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.css index 5edd2cfa21..11c05ab518 100644 --- a/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.css +++ b/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.css @@ -1,157 +1,105 @@ -.progressring { +.progressring { position: relative; width: 2.6em; height: 2.6em; float: left; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; user-select: none; - -webkit-box-sizing: border-box; - box-sizing: border-box + box-sizing: border-box; } .progressring-bg { width: 100%; height: 100%; - -webkit-border-radius: 50%; border-radius: 50%; border: .25em solid rgba(0, 0, 0, 1); - -webkit-box-sizing: border-box; box-sizing: border-box; background: rgba(0, 0, 0, .9); - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center -} - -.spiner-holder-one, -.spiner-holder-two { - position: absolute; - top: 0; - left: 0; - overflow: hidden; - background: 0 0; - -webkit-box-sizing: border-box + justify-content: center; } .progressring-text { text-align: center; color: #ddd; - font-size: 90% + font-size: 90%; } .spiner-holder-one { + position: absolute; + top: 0; + left: 0; + overflow: hidden; width: 51%; height: 51%; - box-sizing: border-box + background: transparent; + box-sizing: border-box; } .spiner-holder-two { + position: absolute; + top: 0; + left: 0; + overflow: hidden; width: 100%; height: 100%; - box-sizing: border-box + background: transparent; + box-sizing: border-box; } .progressring-spiner { width: 200%; height: 200%; - -webkit-border-radius: 50%; border-radius: 50%; border-width: .25em; border-style: solid; - -webkit-box-sizing: border-box; - box-sizing: border-box + box-sizing: border-box; } .animate-0-25-a { - -webkit-transform: rotate(90deg); transform: rotate(90deg); - -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; - -webkit-transition: -webkit-transform 180ms ease-out; - -o-transition: transform 180ms ease-out; - transition: transform 180ms ease-out -} - -.animate-0-25-b, -.animate-25-50-a { - -webkit-transition: -webkit-transform 180ms ease-out; - -o-transition: transform 180ms ease-out + transition: transform 180ms ease-out; } .animate-0-25-b { - -webkit-transform: rotate(-90deg); transform: rotate(-90deg); - -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; - transition: transform 180ms ease-out + transition: transform 180ms ease-out; } .animate-25-50-a { - -webkit-transform: rotate(180deg); transform: rotate(180deg); - -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; - transition: transform 180ms ease-out -} - -.animate-25-50-b, -.animate-50-75-a { - -webkit-transition: -webkit-transform 180ms ease-out; - -o-transition: transform 180ms ease-out + transition: transform 180ms ease-out; } .animate-25-50-b { - -webkit-transform: rotate(-90deg); transform: rotate(-90deg); - -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; - transition: transform 180ms ease-out + transition: transform 180ms ease-out; } .animate-50-75-a { - -webkit-transform: rotate(270deg); transform: rotate(270deg); - -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; - transition: transform 180ms ease-out -} - -.animate-50-75-b, -.animate-75-100-a { - -webkit-transition: -webkit-transform 180ms ease-out; - -o-transition: transform 180ms ease-out + transition: transform 180ms ease-out; } .animate-50-75-b { - -webkit-transform: rotate(-90deg); transform: rotate(-90deg); - -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; - transition: transform 180ms ease-out + transition: transform 180ms ease-out; } .animate-75-100-a { - -webkit-transform: rotate(0); - transform: rotate(0); - -webkit-transform-origin: 100% 100%; + transform: rotate(0deg); transform-origin: 100% 100%; - transition: transform 180ms ease-out + transition: transform 180ms ease-out; } .animate-75-100-b { - -webkit-transform: rotate(-90deg); transform: rotate(-90deg); - -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; - -webkit-transition: -webkit-transform 180ms ease-out; - -o-transition: transform 180ms ease-out; - transition: transform 180ms ease-out -} \ No newline at end of file + transition: transform 180ms ease-out; +} diff --git a/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.js b/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.js index c5358f32e2..feb4ddb20d 100644 --- a/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.js +++ b/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.js @@ -1,21 +1,105 @@ -define(["require", "css!./emby-progressring", "registerElement"], function(require) { - "use strict"; +define(['require', 'css!./emby-progressring', 'registerElement'], function (require) { + 'use strict'; + var EmbyProgressRing = Object.create(HTMLDivElement.prototype); - return EmbyProgressRing.createdCallback = function() { - this.classList.add("progressring"); + + EmbyProgressRing.createdCallback = function () { + + this.classList.add('progressring'); var instance = this; - require(["text!./emby-progressring.template.html"], function(template) { - instance.innerHTML = template, instance.setProgress(parseFloat(instance.getAttribute("data-progress") || "0")) - }) - }, EmbyProgressRing.setProgress = function(progress) { + + require(['text!./emby-progressring.template.html'], function (template) { + instance.innerHTML = template; + + //if (window.MutationObserver) { + // // create an observer instance + // var observer = new MutationObserver(function (mutations) { + // mutations.forEach(function (mutation) { + + // instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0')); + // }); + // }); + + // // configuration of the observer: + // var config = { attributes: true, childList: false, characterData: false }; + + // // pass in the target node, as well as the observer options + // observer.observe(instance, config); + + // instance.observer = observer; + //} + + instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0')); + }); + }; + + EmbyProgressRing.setProgress = function (progress) { + progress = Math.floor(progress); + var angle; - progress < 25 ? (angle = progress / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "rotate(" + angle + "deg)", this.querySelector(".animate-25-50-b").style.transform = "rotate(-90deg)", this.querySelector(".animate-50-75-b").style.transform = "rotate(-90deg)", this.querySelector(".animate-75-100-b").style.transform = "rotate(-90deg)") : progress >= 25 && progress < 50 ? (angle = (progress - 25) / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "none", this.querySelector(".animate-25-50-b").style.transform = "rotate(" + angle + "deg)", this.querySelector(".animate-50-75-b").style.transform = "rotate(-90deg)", this.querySelector(".animate-75-100-b").style.transform = "rotate(-90deg)") : progress >= 50 && progress < 75 ? (angle = (progress - 50) / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "none", this.querySelector(".animate-25-50-b").style.transform = "none", this.querySelector(".animate-50-75-b").style.transform = "rotate(" + angle + "deg)", this.querySelector(".animate-75-100-b").style.transform = "rotate(-90deg)") : progress >= 75 && progress <= 100 && (angle = (progress - 75) / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "none", this.querySelector(".animate-25-50-b").style.transform = "none", this.querySelector(".animate-50-75-b").style.transform = "none", this.querySelector(".animate-75-100-b").style.transform = "rotate(" + angle + "deg)"), this.querySelector(".progressring-text").innerHTML = progress + "%" - }, EmbyProgressRing.attachedCallback = function() {}, EmbyProgressRing.detachedCallback = function() { + + if (progress < 25) { + angle = -90 + (progress / 100) * 360; + + this.querySelector('.animate-0-25-b').style.transform = 'rotate(' + angle + 'deg)'; + + this.querySelector('.animate-25-50-b').style.transform = 'rotate(-90deg)'; + this.querySelector('.animate-50-75-b').style.transform = 'rotate(-90deg)'; + this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)'; + } + else if (progress >= 25 && progress < 50) { + + angle = -90 + ((progress - 25) / 100) * 360; + + this.querySelector('.animate-0-25-b').style.transform = 'none'; + this.querySelector('.animate-25-50-b').style.transform = 'rotate(' + angle + 'deg)'; + + this.querySelector('.animate-50-75-b').style.transform = 'rotate(-90deg)'; + this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)'; + } + else if (progress >= 50 && progress < 75) { + angle = -90 + ((progress - 50) / 100) * 360; + + this.querySelector('.animate-0-25-b').style.transform = 'none'; + this.querySelector('.animate-25-50-b').style.transform = 'none'; + this.querySelector('.animate-50-75-b').style.transform = 'rotate(' + angle + 'deg)'; + + this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)'; + } + else if (progress >= 75 && progress <= 100) { + angle = -90 + ((progress - 75) / 100) * 360; + + this.querySelector('.animate-0-25-b').style.transform = 'none'; + this.querySelector('.animate-25-50-b').style.transform = 'none'; + this.querySelector('.animate-50-75-b').style.transform = 'none'; + this.querySelector('.animate-75-100-b').style.transform = 'rotate(' + angle + 'deg)'; + } + + this.querySelector('.progressring-text').innerHTML = progress + '%'; + }; + + EmbyProgressRing.attachedCallback = function () { + + }; + + EmbyProgressRing.detachedCallback = function () { + + var observer = this.observer; - observer && (observer.disconnect(), this.observer = null) - }, document.registerElement("emby-progressring", { + + if (observer) { + // later, you can stop observing + observer.disconnect(); + + this.observer = null; + } + }; + + document.registerElement('emby-progressring', { prototype: EmbyProgressRing, - extends: "div" - }), EmbyProgressRing + extends: 'div' + }); + + return EmbyProgressRing; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-radio/emby-radio.css b/src/bower_components/emby-webcomponents/emby-radio/emby-radio.css index 382919ac1f..c10d89acb0 100644 --- a/src/bower_components/emby-webcomponents/emby-radio/emby-radio.css +++ b/src/bower_components/emby-webcomponents/emby-radio/emby-radio.css @@ -2,26 +2,26 @@ position: relative; line-height: 24px; display: inline-block; - -webkit-box-sizing: border-box; box-sizing: border-box; margin: 0; - padding-left: 24px + padding-left: 0; } .radio-label-block { - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; margin-top: .5em; - margin-bottom: .5em + margin-bottom: .5em; +} + +.mdl-radio { + padding-left: 24px; } .mdl-radio__button { line-height: 24px; position: absolute; + /* 1px is for focusing purposes, so the focusManager doesn't skip over it */ width: 1px; height: 1px; margin: 0; @@ -31,7 +31,7 @@ -moz-appearance: none; -webkit-appearance: none; appearance: none; - border: none + border: none; } .mdl-radio__outer-circle { @@ -39,25 +39,23 @@ top: 4px; left: 0; display: inline-block; - -webkit-box-sizing: border-box; box-sizing: border-box; width: 16px; height: 16px; margin: 0; cursor: pointer; border: 2px solid currentcolor; - -webkit-border-radius: 50%; border-radius: 50%; - z-index: 2 + z-index: 2; } -.mdl-radio__button:checked+.mdl-radio__label+.mdl-radio__outer-circle { - border: 2px solid #00a4dc +.mdl-radio__button:checked + .mdl-radio__label + .mdl-radio__outer-circle { + border: 2px solid rgb(82, 181, 75); } -.mdl-radio__button:disabled+.mdl-radio__label+.mdl-radio__outer-circle { - border: 2px solid rgba(0, 0, 0, .26); - cursor: auto +.mdl-radio__button:disabled + .mdl-radio__label + .mdl-radio__outer-circle { + border: 2px solid rgba(0,0,0, 0.26); + cursor: auto; } .mdl-radio__inner-circle { @@ -66,52 +64,44 @@ margin: 0; top: 8px; left: 4px; - -webkit-box-sizing: border-box; box-sizing: border-box; width: 8px; height: 8px; cursor: pointer; - -webkit-transition-duration: .28s; - -o-transition-duration: .28s; - transition-duration: .28s; - -webkit-transition-timing-function: cubic-bezier(.4, 0, .2, 1); - -o-transition-timing-function: cubic-bezier(.4, 0, .2, 1); - transition-timing-function: cubic-bezier(.4, 0, .2, 1); - -o-transition-property: transform; - -webkit-transition-property: -webkit-transform, -webkit-transform; + transition-duration: 0.28s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-property: -webkit-transform; + transition-property: transform; transition-property: transform, -webkit-transform; -webkit-transform: scale3d(0, 0, 0); transform: scale3d(0, 0, 0); - -webkit-border-radius: 50%; border-radius: 50%; - background: #00a4dc + background: rgb(82, 181, 75); } -.mdl-radio__button:checked+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle { +.mdl-radio__button:checked + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle { -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1) + transform: scale3d(1, 1, 1); } -.mdl-radio__button:disabled+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle { - background: rgba(0, 0, 0, .26); - cursor: auto +.mdl-radio__button:disabled + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle { + background: rgba(0,0,0, 0.26); + cursor: auto; } -.mdl-radio__button:focus+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle { - -webkit-box-shadow: 0 0 0 10px rgba(255, 255, 255, .76); - box-shadow: 0 0 0 10px rgba(255, 255, 255, .76) +.mdl-radio__button:focus + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle { + box-shadow: 0 0 0px 10px rgba(255, 255, 255, 0.76); } -.mdl-radio__button:checked:focus+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle { - -webkit-box-shadow: 0 0 0 10px rgba(0,164,220, .26); - box-shadow: 0 0 0 10px rgba(0,164,220, .26) +.mdl-radio__button:checked:focus + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle { + box-shadow: 0 0 0px 10px rgba(82, 181, 75, 0.26); } .mdl-radio__label { - cursor: pointer + cursor: pointer; } -.mdl-radio__button:disabled+.mdl-radio__label { - color: rgba(0, 0, 0, .26); - cursor: auto -} \ No newline at end of file +.mdl-radio__button:disabled + .mdl-radio__label { + color: rgba(0,0,0, 0.26); + cursor: auto; +} diff --git a/src/bower_components/emby-webcomponents/emby-radio/emby-radio.js b/src/bower_components/emby-webcomponents/emby-radio/emby-radio.js index a41b3ed06d..6e3b6b9bf4 100644 --- a/src/bower_components/emby-webcomponents/emby-radio/emby-radio.js +++ b/src/bower_components/emby-webcomponents/emby-radio/emby-radio.js @@ -1,20 +1,48 @@ -define(["css!./emby-radio", "registerElement"], function() { - "use strict"; +define(['css!./emby-radio', 'registerElement'], function () { + 'use strict'; + + var EmbyRadioPrototype = Object.create(HTMLInputElement.prototype); function onKeyDown(e) { - if (13 === e.keyCode) return e.preventDefault(), this.checked = !0, !1 - } - var EmbyRadioPrototype = Object.create(HTMLInputElement.prototype); - EmbyRadioPrototype.attachedCallback = function() { - if ("true" !== this.getAttribute("data-radio")) { - this.setAttribute("data-radio", "true"), this.classList.add("mdl-radio__button"); - var labelElement = this.parentNode; - labelElement.classList.add("mdl-radio"), labelElement.classList.add("mdl-js-radio"), labelElement.classList.add("mdl-js-ripple-effect"); - var labelTextElement = labelElement.querySelector("span"); - labelTextElement.classList.add("radioButtonLabel"), labelTextElement.classList.add("mdl-radio__label"), labelElement.insertAdjacentHTML("beforeend", ''), this.addEventListener("keydown", onKeyDown) + + // Don't submit form on enter + if (e.keyCode === 13) { + e.preventDefault(); + + this.checked = true; + + return false; } - }, document.registerElement("emby-radio", { + } + + EmbyRadioPrototype.attachedCallback = function () { + + if (this.getAttribute('data-radio') === 'true') { + return; + } + + this.setAttribute('data-radio', 'true'); + + this.classList.add('mdl-radio__button'); + + var labelElement = this.parentNode; + //labelElement.classList.add('"mdl-radio mdl-js-radio mdl-js-ripple-effect'); + labelElement.classList.add('mdl-radio'); + labelElement.classList.add('mdl-js-radio'); + labelElement.classList.add('mdl-js-ripple-effect'); + + var labelTextElement = labelElement.querySelector('span'); + + labelTextElement.classList.add('radioButtonLabel'); + labelTextElement.classList.add('mdl-radio__label'); + + labelElement.insertAdjacentHTML('beforeend', ''); + + this.addEventListener('keydown', onKeyDown); + }; + + document.registerElement('emby-radio', { prototype: EmbyRadioPrototype, - extends: "input" - }) + extends: 'input' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.css b/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.css index 39408352e0..5e404e780d 100644 --- a/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.css +++ b/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.css @@ -1,67 +1,60 @@ .emby-scrollbuttons-scroller { - position: relative + position: relative; } .scrollbuttoncontainer { position: absolute; top: 0; bottom: 0; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; z-index: 1; font-size: 3em; color: #fff; display: none; - overflow: hidden + overflow: hidden; } .scrollbuttoncontainer-left { background: rgba(20, 20, 20, .5); - background: -webkit-linear-gradient(left, #000 0, rgba(0, 0, 0, 0) 100%); - background: -webkit-gradient(linear, left top, right top, from(#000), to(rgba(0, 0, 0, 0))); - background: -webkit-linear-gradient(left, #000, rgba(0, 0, 0, 0)); - background: -o-linear-gradient(left, #000, rgba(0, 0, 0, 0)); - background: linear-gradient(to right, #000, rgba(0, 0, 0, 0)); - left: 0 + background: -moz-linear-gradient(left,#000 0,rgba(0,0,0,0) 100%); + background: -webkit-linear-gradient(left,#000 0,rgba(0,0,0,0) 100%); + background: linear-gradient(to right,#000,rgba(0,0,0,0)); } .scrollbuttoncontainer-right { background: rgba(20, 20, 20, .5); - background: -webkit-linear-gradient(right, #000 0, rgba(0, 0, 0, 0) 100%); - background: -webkit-gradient(linear, right top, left top, from(#000), to(rgba(0, 0, 0, 0))); - background: -webkit-linear-gradient(right, #000, rgba(0, 0, 0, 0)); - background: -o-linear-gradient(right, #000, rgba(0, 0, 0, 0)); - background: linear-gradient(to left, #000, rgba(0, 0, 0, 0)); - right: 0 + background: -moz-linear-gradient(right,#000 0,rgba(0,0,0,0) 100%); + background: -webkit-linear-gradient(right,#000 0,rgba(0,0,0,0) 100%); + background: linear-gradient(to left,#000,rgba(0,0,0,0)); } .emby-scrollbuttons-scroller:hover .scrollbuttoncontainer { - display: -webkit-box; - display: -webkit-flex; - display: flex + display: flex; +} + +.scrollbuttoncontainer-left { + left: 0; +} + +.scrollbuttoncontainer-right { + right: 0; } .emby-scrollbuttons-scrollbutton { margin: 0 -.2em; - -webkit-transition: -webkit-transform 160ms ease-out; - -o-transition: transform 160ms ease-out; - transition: transform 160ms ease-out + transition: transform 160ms ease-out; } -.scrollbuttoncontainer:hover>.emby-scrollbuttons-scrollbutton { - -webkit-transform: scale(1.3, 1.3); - transform: scale(1.3, 1.3) +.scrollbuttoncontainer:hover > .emby-scrollbuttons-scrollbutton { + transform: scale(1.3, 1.3); } .emby-scrollbuttons-scrollbutton:after { content: ''; - display: none !important + display: none !important; } .emby-scrollbuttons-scrollbutton:focus { - color: inherit !important -} \ No newline at end of file + color: inherit !important; +} diff --git a/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.js b/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.js index fc9c7be825..cd285a8769 100644 --- a/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.js +++ b/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.js @@ -1,75 +1,201 @@ -define(["layoutManager", "dom", "css!./emby-scrollbuttons", "registerElement", "paper-icon-button-light"], function(layoutManager, dom) { - "use strict"; +define(['layoutManager', 'dom', 'css!./emby-scrollbuttons', 'registerElement', 'paper-icon-button-light'], function (layoutManager, dom) { + 'use strict'; + + var EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype); + + EmbyScrollButtonsPrototype.createdCallback = function () { + + }; function getScrollButtonContainerHtml(direction) { - var html = ""; - html += '
'; - var icon = "left" === direction ? "" : ""; - return html += '", html += "
" + + var html = ''; + + var hide = direction === 'left' ? ' hide' : ''; + html += '
'; + + var icon = direction === 'left' ? '' : ''; + + html += ''; + + html += '
'; + + return html; } function getScrollPosition(parent) { - return parent.getScrollPosition ? parent.getScrollPosition() : 0 + + if (parent.getScrollPosition) { + return parent.getScrollPosition(); + } + + return 0; } function getScrollWidth(parent) { - return parent.getScrollSize ? parent.getScrollSize() : 0 + + if (parent.getScrollSize) { + return parent.getScrollSize(); + } + + return 0; } function onScrolledToPosition(scrollButtons, pos, scrollWidth) { - pos > 0 ? scrollButtons.scrollButtonsLeft.classList.remove("hide") : scrollButtons.scrollButtonsLeft.classList.add("hide"), scrollWidth > 0 && (pos += scrollButtons.offsetWidth, pos >= scrollWidth ? scrollButtons.scrollButtonsRight.classList.add("hide") : scrollButtons.scrollButtonsRight.classList.remove("hide")) + + if (pos > 0) { + scrollButtons.scrollButtonsLeft.classList.remove('hide'); + } else { + scrollButtons.scrollButtonsLeft.classList.add('hide'); + } + + if (scrollWidth > 0) { + + pos += scrollButtons.offsetWidth; + + if (pos >= scrollWidth) { + scrollButtons.scrollButtonsRight.classList.add('hide'); + } else { + scrollButtons.scrollButtonsRight.classList.remove('hide'); + } + } } function onScroll(e) { - var scrollButtons = this, - scroller = this.scroller; - onScrolledToPosition(scrollButtons, getScrollPosition(scroller), getScrollWidth(scroller)) + + var scrollButtons = this; + var scroller = this.scroller; + var pos = getScrollPosition(scroller); + var scrollWidth = getScrollWidth(scroller); + + onScrolledToPosition(scrollButtons, pos, scrollWidth); } function getStyleValue(style, name) { + var value = style.getPropertyValue(name); - return value && (value = value.replace("px", "")) ? (value = parseInt(value), isNaN(value) ? 0 : value) : 0 + + if (!value) { + return 0; + } + + value = value.replace('px', ''); + + if (!value) { + return 0; + } + + value = parseInt(value); + if (isNaN(value)) { + return 0; + } + + return value; } function getScrollSize(elem) { - var scrollSize = elem.offsetWidth, - style = window.getComputedStyle(elem, null), - paddingLeft = getStyleValue(style, "padding-left"); - paddingLeft && (scrollSize -= paddingLeft); - var paddingRight = getStyleValue(style, "padding-right"); - paddingRight && (scrollSize -= paddingRight); + + var scrollSize = elem.offsetWidth; + + var style = window.getComputedStyle(elem, null); + + var paddingLeft = getStyleValue(style, 'padding-left'); + + if (paddingLeft) { + scrollSize -= paddingLeft; + } + var paddingRight = getStyleValue(style, 'padding-right'); + + if (paddingRight) { + scrollSize -= paddingRight; + } + var slider = elem.getScrollSlider(); - return style = window.getComputedStyle(slider, null), paddingLeft = getStyleValue(style, "padding-left"), paddingLeft && (scrollSize -= paddingLeft), paddingRight = getStyleValue(style, "padding-right"), paddingRight && (scrollSize -= paddingRight), scrollSize + style = window.getComputedStyle(slider, null); + + paddingLeft = getStyleValue(style, 'padding-left'); + + if (paddingLeft) { + scrollSize -= paddingLeft; + } + paddingRight = getStyleValue(style, 'padding-right'); + + if (paddingRight) { + scrollSize -= paddingRight; + } + + return scrollSize; } function onScrollButtonClick(e) { - var newPos, parent = dom.parentWithAttribute(this, "is", "emby-scroller"), - direction = this.getAttribute("data-direction"), - scrollSize = getScrollSize(parent), - pos = getScrollPosition(parent); - newPos = "left" === direction ? Math.max(0, pos - scrollSize) : pos + scrollSize, parent.scrollToPosition(newPos, !1) + + var parent = dom.parentWithAttribute(this, 'is', 'emby-scroller'); + + var direction = this.getAttribute('data-direction'); + + var scrollSize = getScrollSize(parent); + + var pos = getScrollPosition(parent); + var newPos; + + if (direction === 'left') { + newPos = Math.max(0, pos - scrollSize); + } else { + newPos = pos + scrollSize; + } + + parent.scrollToPosition(newPos, false); } - var EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype); - EmbyScrollButtonsPrototype.createdCallback = function() {}, EmbyScrollButtonsPrototype.attachedCallback = function() { - var parent = dom.parentWithAttribute(this, "is", "emby-scroller"); - this.scroller = parent, parent.classList.add("emby-scrollbuttons-scroller"), this.innerHTML = getScrollButtonContainerHtml("left") + getScrollButtonContainerHtml("right"); + + EmbyScrollButtonsPrototype.attachedCallback = function () { + + var parent = dom.parentWithAttribute(this, 'is', 'emby-scroller'); + this.scroller = parent; + + parent.classList.add('emby-scrollbuttons-scroller'); + + this.innerHTML = getScrollButtonContainerHtml('left') + getScrollButtonContainerHtml('right'); + var scrollHandler = onScroll.bind(this); this.scrollHandler = scrollHandler; - var buttons = this.querySelectorAll(".emby-scrollbuttons-scrollbutton"); - buttons[0].addEventListener("click", onScrollButtonClick), buttons[1].addEventListener("click", onScrollButtonClick), buttons = this.querySelectorAll(".scrollbuttoncontainer"), this.scrollButtonsLeft = buttons[0], this.scrollButtonsRight = buttons[1], parent.addScrollEventListener(scrollHandler, { - capture: !1, - passive: !0 - }) - }, EmbyScrollButtonsPrototype.detachedCallback = function() { + + var buttons = this.querySelectorAll('.emby-scrollbuttons-scrollbutton'); + buttons[0].addEventListener('click', onScrollButtonClick); + buttons[1].addEventListener('click', onScrollButtonClick); + + buttons = this.querySelectorAll('.scrollbuttoncontainer'); + this.scrollButtonsLeft = buttons[0]; + this.scrollButtonsRight = buttons[1]; + + parent.addScrollEventListener(scrollHandler, { + capture: false, + passive: true + }); + }; + + EmbyScrollButtonsPrototype.detachedCallback = function () { + var parent = this.scroller; this.scroller = null; + var scrollHandler = this.scrollHandler; - parent && scrollHandler && parent.removeScrollEventListener(scrollHandler, { - capture: !1, - passive: !0 - }), this.scrollHandler = null, this.scrollButtonsLeft = null, this.scrollButtonsRight = null - }, document.registerElement("emby-scrollbuttons", { + + if (parent && scrollHandler) { + parent.removeScrollEventListener(scrollHandler, { + capture: false, + passive: true + }); + } + + this.scrollHandler = null; + this.scrollButtonsLeft = null; + this.scrollButtonsRight = null; + }; + + document.registerElement('emby-scrollbuttons', { prototype: EmbyScrollButtonsPrototype, - extends: "div" - }) + extends: 'div' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-scroller/emby-scroller.js b/src/bower_components/emby-webcomponents/emby-scroller/emby-scroller.js index d358666f97..6237fd99f6 100644 --- a/src/bower_components/emby-webcomponents/emby-scroller/emby-scroller.js +++ b/src/bower_components/emby-webcomponents/emby-scroller/emby-scroller.js @@ -1,101 +1,224 @@ -define(["scroller", "dom", "layoutManager", "inputManager", "focusManager", "browser", "registerElement"], function(scroller, dom, layoutManager, inputManager, focusManager, browser) { - "use strict"; +define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'browser', 'registerElement'], function (scroller, dom, layoutManager, inputManager, focusManager, browser) { + 'use strict'; + + var ScrollerProtoType = Object.create(HTMLDivElement.prototype); + + ScrollerProtoType.createdCallback = function () { + this.classList.add('emby-scroller'); + }; function initCenterFocus(elem, scrollerInstance) { - dom.addEventListener(elem, "focus", function(e) { + + dom.addEventListener(elem, 'focus', function (e) { + var focused = focusManager.focusableParent(e.target); - focused && scrollerInstance.toCenter(focused) + + if (focused) { + scrollerInstance.toCenter(focused); + } + }, { - capture: !0, - passive: !0 - }) + capture: true, + passive: true + }); } + ScrollerProtoType.scrollToBeginning = function () { + if (this.scroller) { + this.scroller.slideTo(0, true); + } + }; + ScrollerProtoType.toStart = function (elem, immediate) { + if (this.scroller) { + this.scroller.toStart(elem, immediate); + } + }; + ScrollerProtoType.toCenter = function (elem, immediate) { + if (this.scroller) { + this.scroller.toCenter(elem, immediate); + } + }; + + ScrollerProtoType.scrollToPosition = function (pos, immediate) { + if (this.scroller) { + this.scroller.slideTo(pos, immediate); + } + }; + + ScrollerProtoType.getScrollPosition = function () { + if (this.scroller) { + return this.scroller.getScrollPosition(); + } + }; + + ScrollerProtoType.getScrollSize = function () { + if (this.scroller) { + return this.scroller.getScrollSize(); + } + }; + + ScrollerProtoType.getScrollEventName = function () { + if (this.scroller) { + return this.scroller.getScrollEventName(); + } + }; + + ScrollerProtoType.getScrollSlider = function () { + if (this.scroller) { + return this.scroller.getScrollSlider(); + } + }; + + ScrollerProtoType.addScrollEventListener = function (fn, options) { + if (this.scroller) { + dom.addEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options); + } + }; + + ScrollerProtoType.removeScrollEventListener = function (fn, options) { + if (this.scroller) { + dom.removeEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options); + } + }; + function onInputCommand(e) { + var cmd = e.detail.command; - "end" === cmd ? (focusManager.focusLast(this, "." + this.getAttribute("data-navcommands")), e.preventDefault(), e.stopPropagation()) : "pageup" === cmd ? (focusManager.moveFocus(e.target, this, "." + this.getAttribute("data-navcommands"), -12), e.preventDefault(), e.stopPropagation()) : "pagedown" === cmd && (focusManager.moveFocus(e.target, this, "." + this.getAttribute("data-navcommands"), 12), e.preventDefault(), e.stopPropagation()) + + if (cmd === 'end') { + focusManager.focusLast(this, '.' + this.getAttribute('data-navcommands')); + e.preventDefault(); + e.stopPropagation(); + } + else if (cmd === 'pageup') { + focusManager.moveFocus(e.target, this, '.' + this.getAttribute('data-navcommands'), -12); + e.preventDefault(); + e.stopPropagation(); + } + else if (cmd === 'pagedown') { + focusManager.moveFocus(e.target, this, '.' + this.getAttribute('data-navcommands'), 12); + e.preventDefault(); + e.stopPropagation(); + } } function initHeadroom(elem) { - require(["headroom"], function(Headroom) { + require(['headroom'], function (Headroom) { + var headroom = new Headroom([], { scroller: elem }); - headroom.init(), headroom.add(document.querySelector(".skinHeader")), elem.headroom = headroom - }) + // initialise + headroom.init(); + headroom.add(document.querySelector('.skinHeader')); + elem.headroom = headroom; + }); } + ScrollerProtoType.attachedCallback = function () { + + if (this.getAttribute('data-navcommands')) { + inputManager.on(this, onInputCommand); + } + + var horizontal = this.getAttribute('data-horizontal') !== 'false'; + + var slider = this.querySelector('.scrollSlider'); + + if (horizontal) { + slider.style['white-space'] = 'nowrap'; + } + + var bindHeader = this.getAttribute('data-bindheader') === 'true'; + + var scrollFrame = this; + var enableScrollButtons = layoutManager.desktop && horizontal && this.getAttribute('data-scrollbuttons') !== 'false'; + + var options = { + horizontal: horizontal, + mouseDragging: 1, + mouseWheel: this.getAttribute('data-mousewheel') !== 'false', + touchDragging: 1, + slidee: slider, + scrollBy: 200, + speed: horizontal ? 270 : 240, + //immediateSpeed: pageOptions.immediateSpeed, + elasticBounds: 1, + dragHandle: 1, + scrollWidth: this.getAttribute('data-scrollsize') === 'auto' ? null : 5000000, + autoImmediate: true, + skipSlideToWhenVisible: this.getAttribute('data-skipfocuswhenvisible') === 'true', + dispatchScrollEvent: enableScrollButtons || bindHeader || this.getAttribute('data-scrollevent') === 'true', + hideScrollbar: enableScrollButtons || this.getAttribute('data-hidescrollbar') === 'true', + allowNativeSmoothScroll: this.getAttribute('data-allownativesmoothscroll') === 'true' && !enableScrollButtons, + allowNativeScroll: !enableScrollButtons, + forceHideScrollbars: enableScrollButtons, + + // In edge, with the native scroll, the content jumps around when hovering over the buttons + requireAnimation: enableScrollButtons && browser.edge + }; + + // If just inserted it might not have any height yet - yes this is a hack + this.scroller = new scroller(scrollFrame, options); + this.scroller.init(); + + if (layoutManager.tv && this.getAttribute('data-centerfocus')) { + initCenterFocus(this, this.scroller); + } + + if (bindHeader) { + initHeadroom(this); + } + + if (enableScrollButtons) { + loadScrollButtons(this); + } + }; + function loadScrollButtons(scroller) { - require(["emby-scrollbuttons"], function() { - scroller.insertAdjacentHTML("beforeend", '
') - }) + + require(['emby-scrollbuttons'], function () { + scroller.insertAdjacentHTML('beforeend', '
'); + }); } - var ScrollerProtoType = Object.create(HTMLDivElement.prototype); - ScrollerProtoType.createdCallback = function() { - this.classList.add("emby-scroller") - }, ScrollerProtoType.scrollToBeginning = function() { - this.scroller && this.scroller.slideTo(0, !0) - }, ScrollerProtoType.toStart = function(elem, immediate) { - this.scroller && this.scroller.toStart(elem, immediate) - }, ScrollerProtoType.toCenter = function(elem, immediate) { - this.scroller && this.scroller.toCenter(elem, immediate) - }, ScrollerProtoType.scrollToPosition = function(pos, immediate) { - this.scroller && this.scroller.slideTo(pos, immediate) - }, ScrollerProtoType.getScrollPosition = function() { - if (this.scroller) return this.scroller.getScrollPosition() - }, ScrollerProtoType.getScrollSize = function() { - if (this.scroller) return this.scroller.getScrollSize() - }, ScrollerProtoType.getScrollEventName = function() { - if (this.scroller) return this.scroller.getScrollEventName() - }, ScrollerProtoType.getScrollSlider = function() { - if (this.scroller) return this.scroller.getScrollSlider() - }, ScrollerProtoType.addScrollEventListener = function(fn, options) { - this.scroller && dom.addEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options) - }, ScrollerProtoType.removeScrollEventListener = function(fn, options) { - this.scroller && dom.removeEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options) - }, ScrollerProtoType.attachedCallback = function() { - this.getAttribute("data-navcommands") && inputManager.on(this, onInputCommand); - var horizontal = "false" !== this.getAttribute("data-horizontal"), - slider = this.querySelector(".scrollSlider"); - horizontal && (slider.style["white-space"] = "nowrap"); - var bindHeader = "true" === this.getAttribute("data-bindheader"), - scrollFrame = this, - enableScrollButtons = layoutManager.desktop && horizontal && "false" !== this.getAttribute("data-scrollbuttons"), - options = { - horizontal: horizontal, - mouseDragging: 1, - mouseWheel: "false" !== this.getAttribute("data-mousewheel"), - touchDragging: 1, - slidee: slider, - scrollBy: 200, - speed: horizontal ? 270 : 240, - elasticBounds: 1, - dragHandle: 1, - scrollWidth: "auto" === this.getAttribute("data-scrollsize") ? null : 5e6, - autoImmediate: !0, - skipSlideToWhenVisible: "true" === this.getAttribute("data-skipfocuswhenvisible"), - dispatchScrollEvent: enableScrollButtons || bindHeader || "true" === this.getAttribute("data-scrollevent"), - hideScrollbar: enableScrollButtons || "true" === this.getAttribute("data-hidescrollbar"), - allowNativeSmoothScroll: "true" === this.getAttribute("data-allownativesmoothscroll") && !enableScrollButtons, - allowNativeScroll: !enableScrollButtons, - forceHideScrollbars: enableScrollButtons, - requireAnimation: enableScrollButtons && browser.edge - }; - this.scroller = new scroller(scrollFrame, options), this.scroller.init(), layoutManager.tv && this.getAttribute("data-centerfocus") && initCenterFocus(this, this.scroller), bindHeader && initHeadroom(this), enableScrollButtons && loadScrollButtons(this) - }, ScrollerProtoType.pause = function() { + + ScrollerProtoType.pause = function () { + var headroom = this.headroom; - headroom && headroom.pause() - }, ScrollerProtoType.resume = function() { + if (headroom) { + headroom.pause(); + } + }; + + ScrollerProtoType.resume = function () { + var headroom = this.headroom; - headroom && headroom.resume() - }, ScrollerProtoType.detachedCallback = function() { - this.getAttribute("data-navcommands") && inputManager.off(this, onInputCommand); + if (headroom) { + headroom.resume(); + } + }; + + ScrollerProtoType.detachedCallback = function () { + + if (this.getAttribute('data-navcommands')) { + inputManager.off(this, onInputCommand); + } + var headroom = this.headroom; - headroom && (headroom.destroy(), this.headroom = null); + if (headroom) { + headroom.destroy(); + this.headroom = null; + } + var scrollerInstance = this.scroller; - scrollerInstance && (scrollerInstance.destroy(), this.scroller = null) - }, document.registerElement("emby-scroller", { + if (scrollerInstance) { + scrollerInstance.destroy(); + this.scroller = null; + } + }; + + document.registerElement('emby-scroller', { prototype: ScrollerProtoType, - extends: "div" - }) + extends: 'div' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-select/emby-select.css b/src/bower_components/emby-webcomponents/emby-select/emby-select.css index 1dfe686f53..76b28c4208 100644 --- a/src/bower_components/emby-webcomponents/emby-select/emby-select.css +++ b/src/bower_components/emby-webcomponents/emby-select/emby-select.css @@ -2,91 +2,84 @@ display: block; margin: 0; margin-bottom: 0 !important; + /* Remove select styling */ + /* Font size must the 16px or larger to prevent iOS page zoom on focus */ font-size: 110%; + /* General select styles: change as needed */ font-family: inherit; font-weight: inherit; padding: .5em 1.9em .5em .5em; - -webkit-box-sizing: border-box; + /* Prevent padding from causing width overflow */ box-sizing: border-box; - outline: 0 !important; - -webkit-tap-highlight-color: transparent; - width: 100% + outline: none !important; + -webkit-tap-highlight-color: rgba(0,0,0,0); + width: 100%; } -.emby-select[disabled] { - background: 0 0 !important; - border-color: transparent !important; - color: inherit !important; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none -} + .emby-select[disabled] { + background: none !important; + border-color: transparent !important; + color: inherit !important; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + } -.selectContainer-inline>.emby-select { +.selectContainer-inline > .emby-select { padding: .3em 1.9em .3em .5em; - font-size: inherit + font-size: inherit; } -.selectContainer-inline>.emby-select[disabled] { - padding-left: 0; - padding-right: 0 -} + .selectContainer-inline > .emby-select[disabled] { + padding-left: 0; + padding-right: 0; + } .emby-select::-moz-focus-inner { - border: 0 + border: 0; } .emby-select-focusscale { - -webkit-transition: -webkit-transform 180ms ease-out !important; - -o-transition: transform 180ms ease-out !important; transition: transform 180ms ease-out !important; -webkit-transform-origin: center center; - transform-origin: center center + transform-origin: center center; } -.emby-select-focusscale:focus { - -webkit-transform: scale(1.04); - transform: scale(1.04); - z-index: 1 -} + .emby-select-focusscale:focus { + transform: scale(1.04); + z-index: 1; + } -.emby-select+.fieldDescription { - margin-top: .25em +.emby-select + .fieldDescription { + margin-top: .25em; } .selectContainer { margin-bottom: 1.8em; - position: relative + position: relative; } .selectContainer-inline { - display: -webkit-inline-box; - display: -webkit-inline-flex; display: inline-flex; margin-bottom: 0; - -webkit-box-align: center; - -webkit-align-items: center; - align-items: center + align-items: center; } .selectLabel { display: block; - margin-bottom: .25em + margin-bottom: .25em; } -.selectContainer-inline>.selectLabel { +.selectContainer-inline > .selectLabel { margin-bottom: 0; margin-right: .5em; - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } .emby-select-withcolor { -webkit-appearance: none; - -moz-appearance: none; appearance: none; - -webkit-border-radius: .2em; - border-radius: .2em + border-radius: .2em; } .selectArrowContainer { @@ -94,25 +87,24 @@ right: .3em; top: .2em; color: inherit; - pointer-events: none + pointer-events: none; } -.selectContainer-inline>.selectArrowContainer { +.selectContainer-inline > .selectArrowContainer { top: initial; bottom: .24em; - font-size: 90% + font-size: 90%; } -.emby-select[disabled]+.selectArrowContainer { - display: none +.emby-select[disabled] + .selectArrowContainer { + display: none; } .selectArrow { margin-top: .35em; - font-size: 1.7em + font-size: 1.7em; } .emby-select-iconbutton { - -webkit-align-self: flex-end; - align-self: flex-end -} \ No newline at end of file + align-self: flex-end; +} diff --git a/src/bower_components/emby-webcomponents/emby-select/emby-select.js b/src/bower_components/emby-webcomponents/emby-select/emby-select.js index 25e646fcdb..6783f2f48c 100644 --- a/src/bower_components/emby-webcomponents/emby-select/emby-select.js +++ b/src/bower_components/emby-webcomponents/emby-select/emby-select.js @@ -1,75 +1,168 @@ -define(["layoutManager", "browser", "actionsheet", "css!./emby-select", "registerElement"], function(layoutManager, browser, actionsheet) { - "use strict"; +define(['layoutManager', 'browser', 'actionsheet', 'css!./emby-select', 'registerElement'], function (layoutManager, browser, actionsheet) { + 'use strict'; + + var EmbySelectPrototype = Object.create(HTMLSelectElement.prototype); function enableNativeMenu() { - return !(!browser.edgeUwp && !browser.xboxOne) || !(browser.tizen || browser.orsay || browser.web0s) && (!!browser.tv || !layoutManager.tv) + + if (browser.edgeUwp || browser.xboxOne) { + return true; + } + + // Doesn't seem to work at all + if (browser.tizen || browser.orsay || browser.web0s) { + return false; + } + + // Take advantage of the native input methods + if (browser.tv) { + return true; + } + + if (layoutManager.tv) { + return false; + } + + return true; } function triggerChange(select) { var evt = document.createEvent("HTMLEvents"); - evt.initEvent("change", !1, !0), select.dispatchEvent(evt) + evt.initEvent("change", false, true); + select.dispatchEvent(evt); } function setValue(select, value) { - select.value = value + + select.value = value; } function showActionSheet(select) { - var labelElem = getLabel(select), - title = labelElem ? labelElem.textContent || labelElem.innerText : null; + + var labelElem = getLabel(select); + var title = labelElem ? (labelElem.textContent || labelElem.innerText) : null; + actionsheet.show({ items: select.options, positionTo: select, title: title - }).then(function(value) { - setValue(select, value), triggerChange(select) - }) + + }).then(function (value) { + setValue(select, value); + triggerChange(select); + }); } function getLabel(select) { - for (var elem = select.previousSibling; elem && "LABEL" !== elem.tagName;) elem = elem.previousSibling; - return elem + var elem = select.previousSibling; + while (elem && elem.tagName !== 'LABEL') { + elem = elem.previousSibling; + } + return elem; } function onFocus(e) { var label = getLabel(this); - label && label.classList.add("selectLabelFocused") + if (label) { + label.classList.add('selectLabelFocused'); + } } function onBlur(e) { var label = getLabel(this); - label && label.classList.remove("selectLabelFocused") + if (label) { + label.classList.remove('selectLabelFocused'); + } } function onMouseDown(e) { - e.button || enableNativeMenu() || (e.preventDefault(), showActionSheet(this)) + + // e.button=0 for primary (left) mouse button click + if (!e.button && !enableNativeMenu()) { + e.preventDefault(); + showActionSheet(this); + } } function onKeyDown(e) { + switch (e.keyCode) { + case 13: - return void(enableNativeMenu() || (e.preventDefault(), showActionSheet(this))); + if (!enableNativeMenu()) { + e.preventDefault(); + showActionSheet(this); + } + return; case 37: case 38: case 39: case 40: - return void(layoutManager.tv && e.preventDefault()) + if (layoutManager.tv) { + e.preventDefault(); + } + return; + default: + break; } } - var EmbySelectPrototype = Object.create(HTMLSelectElement.prototype), - inputId = 0; - EmbySelectPrototype.createdCallback = function() { - this.id || (this.id = "embyselect" + inputId, inputId++), browser.firefox || (this.classList.add("emby-select-withcolor"), layoutManager.tv && this.classList.add("emby-select-tv-withcolor")), layoutManager.tv && this.classList.add("emby-select-focusscale"), this.addEventListener("mousedown", onMouseDown), this.addEventListener("keydown", onKeyDown), this.addEventListener("focus", onFocus), this.addEventListener("blur", onBlur) - }, EmbySelectPrototype.attachedCallback = function() { - if (!this.classList.contains("emby-select")) { - this.classList.add("emby-select"); - var label = this.ownerDocument.createElement("label"); - label.innerHTML = this.getAttribute("label") || "", label.classList.add("selectLabel"), label.htmlFor = this.id, this.parentNode.insertBefore(label, this), this.classList.contains("emby-select-withcolor") && this.parentNode.insertAdjacentHTML("beforeend", '
0
') + + var inputId = 0; + + EmbySelectPrototype.createdCallback = function () { + + if (!this.id) { + this.id = 'embyselect' + inputId; + inputId++; } - }, EmbySelectPrototype.setLabel = function(text) { - this.parentNode.querySelector("label").innerHTML = text - }, document.registerElement("emby-select", { + + if (!browser.firefox) { + this.classList.add('emby-select-withcolor'); + + if (layoutManager.tv) { + this.classList.add('emby-select-tv-withcolor'); + } + } + + if (layoutManager.tv) { + this.classList.add('emby-select-focusscale'); + } + + this.addEventListener('mousedown', onMouseDown); + this.addEventListener('keydown', onKeyDown); + + this.addEventListener('focus', onFocus); + this.addEventListener('blur', onBlur); + }; + + EmbySelectPrototype.attachedCallback = function () { + + if (this.classList.contains('emby-select')) { + return; + } + + this.classList.add('emby-select'); + + var label = this.ownerDocument.createElement('label'); + label.innerHTML = this.getAttribute('label') || ''; + label.classList.add('selectLabel'); + label.htmlFor = this.id; + this.parentNode.insertBefore(label, this); + + if (this.classList.contains('emby-select-withcolor')) { + this.parentNode.insertAdjacentHTML('beforeend', '
0
'); + } + }; + + EmbySelectPrototype.setLabel = function (text) { + + var label = this.parentNode.querySelector('label'); + + label.innerHTML = text; + }; + + document.registerElement('emby-select', { prototype: EmbySelectPrototype, - extends: "select" - }) + extends: 'select' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-slider/emby-slider.css b/src/bower_components/emby-webcomponents/emby-slider/emby-slider.css index 38cad647b3..548c1cbccf 100644 --- a/src/bower_components/emby-webcomponents/emby-slider/emby-slider.css +++ b/src/bower_components/emby-webcomponents/emby-slider/emby-slider.css @@ -1,7 +1,7 @@ _:-ms-input-placeholder { -ms-appearance: none; height: 2.223em; - margin: 0 + margin: 0; } .mdl-slider { @@ -11,87 +11,88 @@ _:-ms-input-placeholder { -ms-appearance: none; appearance: none; height: .2em; - background: 0 0; + background: transparent; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; outline: 0; padding: 1em 0; - color: #00a4dc; + color: #52B54B; -webkit-align-self: center; + -ms-flex-item-align: center; align-self: center; z-index: 1; cursor: pointer; margin: 0; - -webkit-tap-highlight-color: transparent; - display: block + /* Disable webkit tap highlighting */ + -webkit-tap-highlight-color: rgba(0,0,0,0); + display: block; + /**************************** Tracks ****************************/ + /**************************** Thumbs ****************************/ + /**************************** 0-value ****************************/ + /**************************** Disabled ****************************/ } -.mdl-slider::-moz-focus-outer { - border: 0 -} + .mdl-slider::-moz-focus-outer { + border: 0; + } -.mdl-slider::-ms-tooltip { - display: none -} + .mdl-slider::-ms-tooltip { + display: none; + } -.mdl-slider::-webkit-slider-runnable-track { - background: 0 0 -} + .mdl-slider::-webkit-slider-runnable-track { + background: transparent; + } -.mdl-slider::-moz-range-track { - background: #444; - border: none -} + .mdl-slider::-moz-range-track { + background: #444; + border: none; + } -.mdl-slider::-moz-range-progress { - background: #00a4dc -} + .mdl-slider::-moz-range-progress { + background: #52B54B; + } -.mdl-slider::-ms-track { - background: 0 0; - color: transparent; - height: .2em; - width: 100%; - border: none -} + .mdl-slider::-ms-track { + background: none; + color: transparent; + height: .2em; + width: 100%; + border: none; + } -.mdl-slider::-ms-fill-lower { - display: none -} + .mdl-slider::-ms-fill-lower { + display: none; + } -.mdl-slider::-ms-fill-upper { - display: none -} + .mdl-slider::-ms-fill-upper { + display: none; + } -.mdl-slider::-webkit-slider-thumb { - -webkit-appearance: none; - width: 1.8em; - height: 1.8em; - -webkit-box-sizing: border-box; - box-sizing: border-box; - -webkit-border-radius: 50%; - border-radius: 50%; - background: #00a4dc; - border: none; - -webkit-transition: -webkit-transform .3s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), -webkit-box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1); - transition: transform .3s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1) -} + .mdl-slider::-webkit-slider-thumb { + -webkit-appearance: none; + width: 1.8em; + height: 1.8em; + box-sizing: border-box; + border-radius: 50%; + background: #52B54B; + border: none; + transition: transform 300ms 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); + } .mdl-slider-hoverthumb::-webkit-slider-thumb { margin-left: -.12em; - -webkit-transform: scale(.7, .7); - transform: scale(.7, .7) + transform: scale(.7, .7); } .mdl-slider:hover::-webkit-slider-thumb { - -webkit-transform: none; - transform: none + transform: none; } .slider-no-webkit-thumb::-webkit-slider-thumb { - opacity: 0 !important + opacity: 0 !important; } .mdl-slider::-moz-range-thumb { @@ -100,8 +101,9 @@ _:-ms-input-placeholder { height: 1.8em; box-sizing: border-box; border-radius: 50%; - background: #00a4dc; - border: none + background-image: none; + background: #52B54B; + border: none; } .mdl-slider::-ms-thumb { @@ -110,30 +112,30 @@ _:-ms-input-placeholder { height: 1.8em; box-sizing: border-box; border-radius: 50%; - background: #00a4dc; + background: #52B54B; border: none; - transition: transform .3s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1) + transition: transform 300ms 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); } .mdl-slider-hoverthumb::-ms-thumb { margin-left: -.4em; - transform: scale(.5, .5) + transform: scale(.5, .5); } .mdl-slider:hover::-ms-thumb { - transform: none + transform: none; } .mdl-slider[disabled]::-webkit-slider-thumb { - display: none + display: none; } .mdl-slider[disabled]::-moz-range-thumb { - display: none + display: none; } .mdl-slider[disabled]::-ms-thumb { - display: none + display: none; } .mdl-slider-ie-container { @@ -141,20 +143,15 @@ _:-ms-input-placeholder { overflow: visible; border: none; margin: 0; - padding: 0 + padding: 0; } .mdl-slider-container { height: 1.25em; position: relative; - background: 0 0; - display: -webkit-box; - display: -webkit-flex; + background: none; display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -webkit-flex-direction: row; - flex-direction: row + flex-direction: row; } .mdl-slider-background-flex { @@ -165,70 +162,62 @@ _:-ms-input-placeholder { width: 100%; top: 50%; left: 0; - display: -webkit-box; - display: -webkit-flex; display: flex; overflow: hidden; border: 0; - padding: 0 + padding: 0; } .mdl-slider-background-flex-inner { position: relative; - width: 100% + width: 100%; } .mdl-slider-background-lower { + /*transition: width 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/ position: absolute; left: 0; width: 0; top: 0; bottom: 0; - background-color: #00a4dc + background-color: #52B54B; } .mdl-slider-background-lower-clear { - background-color: transparent + background-color: transparent; } .mdl-slider-background-lower-withtransform { width: 100%; - -webkit-transform-origin: left center; + /*transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/ transform-origin: left center; - -webkit-transform: scaleX(0); - transform: scaleX(0) + transform: scaleX(0); } .mdl-slider-background-upper { + /*transition: left 0.18s cubic-bezier(0.4, 0, 0.2, 1), width 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/ background: #666; background: rgba(255, 255, 255, .4); position: absolute; left: 0; width: 0; top: 0; - bottom: 0 + bottom: 0; } .sliderBubble { position: absolute; top: 0; left: 0; - -webkit-transform: translate3d(-48%, -120%, 0); transform: translate3d(-48%, -120%, 0); background: #282828; color: #fff; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center + justify-content: center; } .sliderBubbleText { margin: 0; - padding: .5em .75em -} \ No newline at end of file + padding: .5em .75em; +} diff --git a/src/bower_components/emby-webcomponents/emby-slider/emby-slider.js b/src/bower_components/emby-webcomponents/emby-slider/emby-slider.js index 74e160d5b7..06fcdcfea1 100644 --- a/src/bower_components/emby-webcomponents/emby-slider/emby-slider.js +++ b/src/bower_components/emby-webcomponents/emby-slider/emby-slider.js @@ -1,101 +1,270 @@ -define(["browser", "dom", "layoutManager", "css!./emby-slider", "registerElement", "emby-input"], function(browser, dom, layoutManager) { - "use strict"; +define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement', 'emby-input'], function (browser, dom, layoutManager) { + 'use strict'; + + var EmbySliderPrototype = Object.create(HTMLInputElement.prototype); + + var supportsNativeProgressStyle = browser.firefox; + var supportsValueSetOverride = false; + + var enableWidthWithTransform; + + if (Object.getOwnPropertyDescriptor && Object.defineProperty) { + + var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); + // descriptor returning null in webos + if (descriptor && descriptor.configurable) { + supportsValueSetOverride = true; + } + } function updateValues() { - var range = this, - value = range.value; - requestAnimationFrame(function() { + + var range = this; + var value = range.value; + + // put this on a callback. Doing it within the event sometimes causes the slider to get hung up and not respond + requestAnimationFrame(function () { + var backgroundLower = range.backgroundLower; + if (backgroundLower) { var fraction = (value - range.min) / (range.max - range.min); - enableWidthWithTransform ? backgroundLower.style.transform = "scaleX(" + fraction + ")" : (fraction *= 100, backgroundLower.style.width = fraction + "%") + + if (enableWidthWithTransform) { + backgroundLower.style.transform = 'scaleX(' + (fraction) + ')'; + } else { + fraction *= 100; + backgroundLower.style.width = fraction + '%'; + } } - }) + }); } function updateBubble(range, value, bubble, bubbleText) { - requestAnimationFrame(function() { - bubble.style.left = value + "%", range.getBubbleHtml ? value = range.getBubbleHtml(value) : (value = range.getBubbleText ? range.getBubbleText(value) : Math.round(value), value = '

' + value + "

"), bubble.innerHTML = value - }) + + requestAnimationFrame(function () { + + bubble.style.left = value + '%'; + + if (range.getBubbleHtml) { + value = range.getBubbleHtml(value); + } else { + if (range.getBubbleText) { + value = range.getBubbleText(value); + } else { + value = Math.round(value); + } + value = '

' + value + '

'; + } + + bubble.innerHTML = value; + }); } + EmbySliderPrototype.attachedCallback = function () { + + if (this.getAttribute('data-embyslider') === 'true') { + return; + } + + if (enableWidthWithTransform == null) { + //enableWidthWithTransform = browser.supportsCssAnimation(); + } + + this.setAttribute('data-embyslider', 'true'); + + this.classList.add('mdl-slider'); + this.classList.add('mdl-js-slider'); + + if (browser.noFlex) { + this.classList.add('slider-no-webkit-thumb'); + } + if (!layoutManager.mobile) { + this.classList.add('mdl-slider-hoverthumb'); + } + + var containerElement = this.parentNode; + containerElement.classList.add('mdl-slider-container'); + + var htmlToInsert = ''; + + if (!supportsNativeProgressStyle) { + htmlToInsert += '
'; + htmlToInsert += '
'; + + // the more of these, the more ranges we can display + htmlToInsert += '
'; + + if (enableWidthWithTransform) { + htmlToInsert += '
'; + } else { + htmlToInsert += '
'; + } + + htmlToInsert += '
'; + htmlToInsert += '
'; + } + + htmlToInsert += '
'; + + containerElement.insertAdjacentHTML('beforeend', htmlToInsert); + + this.backgroundLower = containerElement.querySelector('.mdl-slider-background-lower'); + this.backgroundUpper = containerElement.querySelector('.mdl-slider-background-upper'); + var sliderBubble = containerElement.querySelector('.sliderBubble'); + + var hasHideClass = sliderBubble.classList.contains('hide'); + + dom.addEventListener(this, 'input', function (e) { + this.dragging = true; + + updateBubble(this, this.value, sliderBubble); + + if (hasHideClass) { + sliderBubble.classList.remove('hide'); + hasHideClass = false; + } + }, { + passive: true + }); + + dom.addEventListener(this, 'change', function () { + this.dragging = false; + updateValues.call(this); + + 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, (window.PointerEvent ? 'pointermove' : '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, bubbleValue, sliderBubble); + + if (hasHideClass) { + sliderBubble.classList.remove('hide'); + hasHideClass = false; + } + } + + }, { + passive: true + }); + + dom.addEventListener(this, (window.PointerEvent ? 'pointerleave' : 'mouseleave'), function () { + sliderBubble.classList.add('hide'); + hasHideClass = true; + }, { + passive: true + }); + } + + if (!supportsNativeProgressStyle) { + + if (supportsValueSetOverride) { + this.addEventListener('valueset', updateValues); + } else { + startInterval(this); + } + } + }; + function setRange(elem, startPercent, endPercent) { + var style = elem.style; - style.left = Math.max(startPercent, 0) + "%"; + style.left = Math.max(startPercent, 0) + '%'; + var widthPercent = endPercent - startPercent; - style.width = Math.max(Math.min(widthPercent, 100), 0) + "%" + style.width = Math.max(Math.min(widthPercent, 100), 0) + '%'; } function mapRangesFromRuntimeToPercent(ranges, runtime) { - return runtime ? ranges.map(function(r) { + + if (!runtime) { + return []; + } + + return ranges.map(function (r) { + return { - start: r.start / runtime * 100, - end: r.end / runtime * 100 - } - }) : [] + start: (r.start / runtime) * 100, + end: (r.end / runtime) * 100 + }; + }); } + EmbySliderPrototype.setBufferedRanges = function (ranges, runtime, position) { + + var elem = this.backgroundUpper; + if (!elem) { + return; + } + + if (runtime != null) { + ranges = mapRangesFromRuntimeToPercent(ranges, runtime); + + position = (position / runtime) * 100; + } + + for (var i = 0, length = ranges.length; i < length; i++) { + + var range = ranges[i]; + + if (position != null) { + if (position >= range.end) { + continue; + } + } + + setRange(elem, range.start, range.end); + return; + } + + setRange(elem, 0, 0); + }; + + EmbySliderPrototype.setIsClear = function (isClear) { + + var backgroundLower = this.backgroundLower; + if (backgroundLower) { + if (isClear) { + backgroundLower.classList.add('mdl-slider-background-lower-clear'); + } else { + backgroundLower.classList.remove('mdl-slider-background-lower-clear'); + } + } + }; + function startInterval(range) { var interval = range.interval; - interval && clearInterval(interval), range.interval = setInterval(updateValues.bind(range), 100) - } - var enableWidthWithTransform, EmbySliderPrototype = Object.create(HTMLInputElement.prototype), - supportsNativeProgressStyle = browser.firefox, - supportsValueSetOverride = !1; - if (Object.getOwnPropertyDescriptor && Object.defineProperty) { - var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value"); - descriptor && descriptor.configurable && (supportsValueSetOverride = !0) - } - EmbySliderPrototype.attachedCallback = function() { - if ("true" !== this.getAttribute("data-embyslider")) { - this.setAttribute("data-embyslider", "true"), this.classList.add("mdl-slider"), this.classList.add("mdl-js-slider"), browser.noFlex && this.classList.add("slider-no-webkit-thumb"), layoutManager.mobile || this.classList.add("mdl-slider-hoverthumb"); - var containerElement = this.parentNode; - containerElement.classList.add("mdl-slider-container"); - var htmlToInsert = ""; - supportsNativeProgressStyle || (htmlToInsert += '
', htmlToInsert += '
', htmlToInsert += '
', htmlToInsert += enableWidthWithTransform ? '
' : '
', htmlToInsert += "
", htmlToInsert += "
"), htmlToInsert += '
', containerElement.insertAdjacentHTML("beforeend", htmlToInsert), this.backgroundLower = containerElement.querySelector(".mdl-slider-background-lower"), this.backgroundUpper = containerElement.querySelector(".mdl-slider-background-upper"); - var sliderBubble = containerElement.querySelector(".sliderBubble"), - hasHideClass = sliderBubble.classList.contains("hide"); - dom.addEventListener(this, "input", function(e) { - this.dragging = !0, updateBubble(this, this.value, sliderBubble), hasHideClass && (sliderBubble.classList.remove("hide"), hasHideClass = !1) - }, { - passive: !0 - }), dom.addEventListener(this, "change", function() { - this.dragging = !1, updateValues.call(this), sliderBubble.classList.add("hide"), hasHideClass = !0 - }, { - passive: !0 - }), browser.firefox || (dom.addEventListener(this, window.PointerEvent ? "pointermove" : "mousemove", function(e) { - if (!this.dragging) { - var rect = this.getBoundingClientRect(), - clientX = e.clientX, - bubbleValue = (clientX - rect.left) / rect.width; - bubbleValue *= 100, updateBubble(this, bubbleValue, sliderBubble), hasHideClass && (sliderBubble.classList.remove("hide"), hasHideClass = !1) - } - }, { - passive: !0 - }), dom.addEventListener(this, window.PointerEvent ? "pointerleave" : "mouseleave", function() { - sliderBubble.classList.add("hide"), hasHideClass = !0 - }, { - passive: !0 - })), supportsNativeProgressStyle || (supportsValueSetOverride ? this.addEventListener("valueset", updateValues) : startInterval(this)) + if (interval) { + clearInterval(interval); } - }, EmbySliderPrototype.setBufferedRanges = function(ranges, runtime, position) { - var elem = this.backgroundUpper; - if (elem) { - null != runtime && (ranges = mapRangesFromRuntimeToPercent(ranges, runtime), position = position / runtime * 100); - for (var i = 0, length = ranges.length; i < length; i++) { - var range = ranges[i]; - if (!(null != position && position >= range.end)) return void setRange(elem, range.start, range.end) - } - setRange(elem, 0, 0) - } - }, EmbySliderPrototype.setIsClear = function(isClear) { - var backgroundLower = this.backgroundLower; - backgroundLower && (isClear ? backgroundLower.classList.add("mdl-slider-background-lower-clear") : backgroundLower.classList.remove("mdl-slider-background-lower-clear")) - }, EmbySliderPrototype.detachedCallback = function() { + range.interval = setInterval(updateValues.bind(range), 100); + } + + EmbySliderPrototype.detachedCallback = function () { + var interval = this.interval; - interval && clearInterval(interval), this.interval = null, this.backgroundUpper = null, this.backgroundLower = null - }, document.registerElement("emby-slider", { + if (interval) { + clearInterval(interval); + } + this.interval = null; + this.backgroundUpper = null; + this.backgroundLower = null; + }; + + document.registerElement('emby-slider', { prototype: EmbySliderPrototype, - extends: "input" - }) + extends: 'input' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.css b/src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.css index 56b5124d11..49881994bd 100644 --- a/src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.css +++ b/src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.css @@ -1,43 +1,47 @@ -.emby-tab-button, -.emby-tabs-slider { - position: relative -} - -.emby-tab-button { - background: 0 0; - -webkit-box-shadow: none; +.emby-tab-button { + background: transparent; box-shadow: none; cursor: pointer; - outline: 0 !important; + outline: none !important; width: auto; font-family: inherit; font-size: inherit; display: inline-block; vertical-align: middle; - -webkit-flex-shrink: 0; flex-shrink: 0; margin: 0; padding: 1em .9em; + position: relative; height: auto; min-width: initial; line-height: initial; - -webkit-border-radius: 0 !important; border-radius: 0 !important; overflow: hidden; - font-weight: 600 + font-weight: 600; } -.emby-tab-button.emby-button-tv:focus { - -webkit-transform: scale(1.32); - transform: scale(1.32); - -webkit-transform-origin: center center; - transform-origin: center center + /*.emby-tab-button-active { + color: #52B54B; +} + + .emby-tab-button-active.emby-button-tv { + color: #fff; + }*/ + + .emby-tab-button.emby-button-tv:focus { + /*color: #52B54B;*/ + transform: scale(1.32); + transform-origin: center center; + } + +.emby-tabs-slider { + position: relative; } .emby-tab-button-ripple-effect { - background: rgba(0, 0, 0, .7) !important + background: rgba(0,0,0,.7) !important; } .tabContent:not(.is-active) { - display: none -} \ No newline at end of file + display: none; +} diff --git a/src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.js b/src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.js index 3408072a8a..3642facd2a 100644 --- a/src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.js +++ b/src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.js @@ -1,191 +1,370 @@ -define(["dom", "scroller", "browser", "layoutManager", "focusManager", "registerElement", "css!./emby-tabs", "scrollStyles"], function(dom, scroller, browser, layoutManager, focusManager) { - "use strict"; +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); + var buttonClass = 'emby-tab-button'; + var activeButtonClass = buttonClass + '-active'; function setActiveTabButton(tabs, newButton, oldButton, animate) { - newButton.classList.add(activeButtonClass) + + newButton.classList.add(activeButtonClass); } function getFocusCallback(tabs, e) { - return function() { - onClick.call(tabs, e) - } + return function () { + onClick.call(tabs, e); + }; } function onFocus(e) { - layoutManager.tv && (this.focusTimeout && clearTimeout(this.focusTimeout), this.focusTimeout = setTimeout(getFocusCallback(this, e), 700)) + + if (layoutManager.tv) { + + if (this.focusTimeout) { + clearTimeout(this.focusTimeout); + } + this.focusTimeout = setTimeout(getFocusCallback(this, e), 700); + } } function getTabPanel(tabs, index) { - return null + + return null; } function removeActivePanelClass(tabs, index) { var tabPanel = getTabPanel(tabs, index); - tabPanel && tabPanel.classList.remove("is-active") + if (tabPanel) { + tabPanel.classList.remove('is-active'); + } + } + + function addActivePanelClass(tabs, index) { + var tabPanel = getTabPanel(tabs, index); + if (tabPanel) { + tabPanel.classList.add('is-active'); + } } function fadeInRight(elem) { - var pct = browser.mobile ? "4%" : "0.5%", - keyframes = [{ - opacity: "0", - transform: "translate3d(" + pct + ", 0, 0)", - offset: 0 - }, { - opacity: "1", - transform: "none", - offset: 1 - }]; + + var pct = browser.mobile ? '4%' : '0.5%'; + + var keyframes = [ + { opacity: '0', transform: 'translate3d(' + pct + ', 0, 0)', offset: 0 }, + { opacity: '1', transform: 'none', offset: 1 }]; + elem.animate(keyframes, { duration: 160, iterations: 1, - easing: "ease-out" - }) + easing: 'ease-out' + }); } function triggerBeforeTabChange(tabs, index, previousIndex) { + tabs.dispatchEvent(new CustomEvent("beforetabchange", { detail: { selectedTabIndex: index, previousIndex: previousIndex } - })), null != previousIndex && previousIndex !== index && removeActivePanelClass(tabs, previousIndex); + })); + if (previousIndex != null && previousIndex !== index) { + removeActivePanelClass(tabs, previousIndex); + } + var newPanel = getTabPanel(tabs, index); - newPanel && (newPanel.animate && fadeInRight(newPanel), newPanel.classList.add("is-active")) + + if (newPanel) { + // animate new panel ? + if (newPanel.animate) { + fadeInRight(newPanel); + } + + newPanel.classList.add('is-active'); + } } function onClick(e) { - this.focusTimeout && clearTimeout(this.focusTimeout); - var tabs = this, - current = tabs.querySelector("." + activeButtonClass), - tabButton = dom.parentWithClass(e.target, buttonClass); + + if (this.focusTimeout) { + clearTimeout(this.focusTimeout); + } + + var tabs = this; + + var current = tabs.querySelector('.' + activeButtonClass); + var tabButton = dom.parentWithClass(e.target, buttonClass); + if (tabButton && tabButton !== current) { - current && current.classList.remove(activeButtonClass); - var previousIndex = current ? parseInt(current.getAttribute("data-index")) : null; - setActiveTabButton(tabs, tabButton, current, !0); - var index = parseInt(tabButton.getAttribute("data-index")); - triggerBeforeTabChange(tabs, index, previousIndex), setTimeout(function() { - tabs.selectedTabIndex = index, tabs.dispatchEvent(new CustomEvent("tabchange", { + + if (current) { + current.classList.remove(activeButtonClass); + } + + var previousIndex = current ? parseInt(current.getAttribute('data-index')) : null; + + setActiveTabButton(tabs, tabButton, current, true); + + var index = parseInt(tabButton.getAttribute('data-index')); + + triggerBeforeTabChange(tabs, index, previousIndex); + + // If toCenter is called syncronously within the click event, it sometimes ends up canceling it + setTimeout(function () { + + tabs.selectedTabIndex = index; + + tabs.dispatchEvent(new CustomEvent("tabchange", { detail: { selectedTabIndex: index, previousIndex: previousIndex } - })) - }, 120), tabs.scroller && tabs.scroller.toCenter(tabButton, !1) + })); + }, 120); + + if (tabs.scroller) { + tabs.scroller.toCenter(tabButton, false); + } + } } function initScroller(tabs) { - if (!tabs.scroller) { - var contentScrollSlider = tabs.querySelector(".emby-tabs-slider"); - contentScrollSlider ? (tabs.scroller = new scroller(tabs, { + + if (tabs.scroller) { + return; + } + + var contentScrollSlider = tabs.querySelector('.emby-tabs-slider'); + if (contentScrollSlider) { + tabs.scroller = new scroller(tabs, { horizontal: 1, itemNav: 0, mouseDragging: 1, touchDragging: 1, slidee: contentScrollSlider, - smart: !0, - releaseSwing: !0, + smart: true, + releaseSwing: true, scrollBy: 200, speed: 120, elasticBounds: 1, dragHandle: 1, dynamicHandle: 1, clickBar: 1, - hiddenScroll: !0, + hiddenScroll: true, + + // In safari the transform is causing the headers to occasionally disappear or flicker requireAnimation: !browser.safari, - allowNativeSmoothScroll: !0 - }), tabs.scroller.init()) : (tabs.classList.add("scrollX"), tabs.classList.add("hiddenScrollX"), tabs.classList.add("smoothScrollX")) - } + allowNativeSmoothScroll: true + }); + tabs.scroller.init(); + } else { + tabs.classList.add('scrollX'); + tabs.classList.add('hiddenScrollX'); + tabs.classList.add('smoothScrollX'); + } } + EmbyTabs.createdCallback = function () { + + if (this.classList.contains('emby-tabs')) { + 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 + }); + }; + + 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); + + var current = this.querySelector('.' + activeButtonClass); + var currentIndex = current ? parseInt(current.getAttribute('data-index')) : parseInt(this.getAttribute('data-index') || '0'); + + if (currentIndex !== -1) { + + this.selectedTabIndex = currentIndex; + + var tabButtons = this.querySelectorAll('.' + buttonClass); + + var newTabButton = tabButtons[currentIndex]; + + if (newTabButton) { + setActiveTabButton(this, newTabButton, current, false); + } + } + + if (!this.readyFired) { + this.readyFired = true; + this.dispatchEvent(new CustomEvent("ready", {})); + } + }; + + EmbyTabs.detachedCallback = function () { + + if (this.scroller) { + this.scroller.destroy(); + this.scroller = null; + } + + dom.removeEventListener(this, 'click', onClick, { + passive: true + }); + dom.removeEventListener(this, 'focus', onFocus, { + passive: true, + capture: true + }); + }; + function getSelectedTabButton(elem) { - return elem.querySelector("." + activeButtonClass) + + return elem.querySelector('.' + activeButtonClass); } - function getSibling(elem, method) { - for (var sibling = elem[method]; sibling;) { - if (sibling.classList.contains(buttonClass) && !sibling.classList.contains("hide")) return sibling; - sibling = sibling[method] - } - return null - } - var EmbyTabs = Object.create(HTMLDivElement.prototype), - buttonClass = "emby-tab-button", - activeButtonClass = buttonClass + "-active"; - EmbyTabs.createdCallback = function() { - this.classList.contains("emby-tabs") || (this.classList.add("emby-tabs"), this.classList.add("focusable"), dom.addEventListener(this, "click", onClick, { - passive: !0 - }), dom.addEventListener(this, "focus", onFocus, { - passive: !0, - capture: !0 - })) - }, EmbyTabs.focus = function() { - var selected = this.querySelector("." + activeButtonClass); - selected ? focusManager.focus(selected) : focusManager.autoFocus(this) - }, EmbyTabs.refresh = function() { - this.scroller && this.scroller.reload() - }, EmbyTabs.attachedCallback = function() { - initScroller(this); - var current = this.querySelector("." + activeButtonClass), - currentIndex = current ? parseInt(current.getAttribute("data-index")) : parseInt(this.getAttribute("data-index") || "0"); - if (-1 !== currentIndex) { - this.selectedTabIndex = currentIndex; - var tabButtons = this.querySelectorAll("." + buttonClass), - newTabButton = tabButtons[currentIndex]; - newTabButton && setActiveTabButton(this, newTabButton, current, !1) - } - this.readyFired || (this.readyFired = !0, this.dispatchEvent(new CustomEvent("ready", {}))) - }, EmbyTabs.detachedCallback = function() { - this.scroller && (this.scroller.destroy(), this.scroller = null), dom.removeEventListener(this, "click", onClick, { - passive: !0 - }), dom.removeEventListener(this, "focus", onFocus, { - passive: !0, - capture: !0 - }) - }, EmbyTabs.selectedIndex = function(selected, triggerEvent) { + EmbyTabs.selectedIndex = function (selected, triggerEvent) { + var tabs = this; - if (null == selected) return tabs.selectedTabIndex || 0; + + if (selected == null) { + + return tabs.selectedTabIndex || 0; + } + var current = tabs.selectedIndex(); + tabs.selectedTabIndex = selected; - var tabButtons = tabs.querySelectorAll("." + buttonClass); - if (current === selected || !1 === triggerEvent) { - triggerBeforeTabChange(tabs, selected, current), tabs.dispatchEvent(new CustomEvent("tabchange", { + + var tabButtons = tabs.querySelectorAll('.' + buttonClass); + + if (current === selected || triggerEvent === false) { + + triggerBeforeTabChange(tabs, selected, current); + + tabs.dispatchEvent(new CustomEvent("tabchange", { detail: { selectedTabIndex: selected } })); + var currentTabButton = tabButtons[current]; - setActiveTabButton(tabs, tabButtons[selected], currentTabButton, !1), current !== selected && currentTabButton && currentTabButton.classList.remove(activeButtonClass) - } else onClick.call(tabs, { - target: tabButtons[selected] - }) - }, EmbyTabs.selectNext = function() { - var current = getSelectedTabButton(this), - sibling = getSibling(current, "nextSibling"); - sibling && onClick.call(this, { - target: sibling - }) - }, EmbyTabs.selectPrevious = function() { - var current = getSelectedTabButton(this), - sibling = getSibling(current, "previousSibling"); - sibling && onClick.call(this, { - target: sibling - }) - }, EmbyTabs.triggerBeforeTabChange = function(selected) { + setActiveTabButton(tabs, tabButtons[selected], currentTabButton, false); + + if (current !== selected && currentTabButton) { + currentTabButton.classList.remove(activeButtonClass); + } + + } else { + + onClick.call(tabs, { + target: tabButtons[selected] + }); + //tabButtons[selected].click(); + } + }; + + function getSibling(elem, method) { + + var sibling = elem[method]; + + while (sibling) { + if (sibling.classList.contains(buttonClass)) { + + if (!sibling.classList.contains('hide')) { + return sibling; + } + } + + sibling = sibling[method]; + } + + return null; + } + + EmbyTabs.selectNext = function () { + + var current = getSelectedTabButton(this); + + var sibling = getSibling(current, 'nextSibling'); + + if (sibling) { + onClick.call(this, { + target: sibling + }); + } + }; + + EmbyTabs.selectPrevious = function () { + + var current = getSelectedTabButton(this); + + var sibling = getSibling(current, 'previousSibling'); + + if (sibling) { + onClick.call(this, { + target: sibling + }); + } + }; + + EmbyTabs.triggerBeforeTabChange = function (selected) { + var tabs = this; - triggerBeforeTabChange(tabs, tabs.selectedIndex()) - }, EmbyTabs.triggerTabChange = function(selected) { + + triggerBeforeTabChange(tabs, tabs.selectedIndex()); + }; + + EmbyTabs.triggerTabChange = function (selected) { + var tabs = this; + tabs.dispatchEvent(new CustomEvent("tabchange", { detail: { selectedTabIndex: tabs.selectedIndex() } - })) - }, EmbyTabs.setTabEnabled = function(index, enabled) { + })); + }; + + EmbyTabs.setTabEnabled = function (index, enabled) { + + var tabs = this; var btn = this.querySelector('.emby-tab-button[data-index="' + index + '"]'); - enabled ? btn.classList.remove("hide") : btn.classList.remove("add") - }, document.registerElement("emby-tabs", { + + if (enabled) { + btn.classList.remove('hide'); + } else { + btn.classList.remove('add'); + } + }; + + document.registerElement('emby-tabs', { prototype: EmbyTabs, - extends: "div" - }) + extends: 'div' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.css b/src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.css index 18313cffd1..6ac8262236 100644 --- a/src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.css +++ b/src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.css @@ -2,30 +2,31 @@ display: block; margin: 0; margin-bottom: 0 !important; + /* Remove select styling */ + /* Font size must the 16px or larger to prevent iOS page zoom on focus */ font-size: inherit; + /* General select styles: change as needed */ font-family: inherit; font-weight: inherit; color: inherit; padding: .35em .25em; - -webkit-box-sizing: border-box; + /* Prevent padding from causing width overflow */ box-sizing: border-box; - outline: 0 !important; - -webkit-tap-highlight-color: transparent; - width: 100% + outline: none !important; + -webkit-tap-highlight-color: rgba(0,0,0,0); + width: 100%; } -.emby-textarea::-moz-focus-inner { - border: 0 -} + .emby-textarea::-moz-focus-inner { + border: 0; + } .textareaLabel { display: inline-block; - -webkit-transition: all .2s ease-out; - -o-transition: all .2s ease-out; transition: all .2s ease-out; - margin-bottom: .25em + margin-bottom: .25em; } -.emby-textarea+.fieldDescription { - margin-top: .25em -} \ No newline at end of file +.emby-textarea + .fieldDescription { + margin-top: .25em; +} diff --git a/src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.js b/src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.js index f5725c2301..130d6c3980 100644 --- a/src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.js +++ b/src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.js @@ -1,55 +1,138 @@ -define(["layoutManager", "browser", "css!./emby-textarea", "registerElement", "emby-input"], function(layoutManager, browser) { - "use strict"; +define(['layoutManager', 'browser', 'css!./emby-textarea', 'registerElement', 'emby-input'], function (layoutManager, browser) { + 'use strict'; function autoGrow(textarea, maxLines) { + var self = this; + + if (maxLines === undefined) { + maxLines = 999; + } + + /** + * Calculates the vertical padding of the element + * @param textarea + * @returns {number} + */ + self.getOffset = function (textarea) { + var style = window.getComputedStyle(textarea, null), + props = ['paddingTop', 'paddingBottom'], + offset = 0; + + for (var i = 0; i < props.length; i++) { + offset += parseInt(style[props[i]]); + } + return offset; + }; + + var offset; function reset() { - textarea.rows = 1, offset = self.getOffset(textarea), self.rows = textarea.rows || 1, self.lineHeight = textarea.scrollHeight / self.rows - offset / self.rows, self.maxAllowedHeight = self.lineHeight * maxLines - offset + textarea.rows = 1; + offset = self.getOffset(textarea); + self.rows = textarea.rows || 1; + self.lineHeight = (textarea.scrollHeight / self.rows) - (offset / self.rows); + self.maxAllowedHeight = (self.lineHeight * maxLines) - offset; } function autogrowFn() { - if ((!self.lineHeight || self.lineHeight <= 0) && reset(), self.lineHeight <= 0) return textarea.style.overflowY = "scroll", textarea.style.height = "auto", void(textarea.rows = 3); - var newHeight = 0; - textarea.scrollHeight - offset > self.maxAllowedHeight ? (textarea.style.overflowY = "scroll", newHeight = self.maxAllowedHeight) : (textarea.style.overflowY = "hidden", textarea.style.height = "auto", newHeight = textarea.scrollHeight), textarea.style.height = newHeight + "px" + if (!self.lineHeight || self.lineHeight <= 0) { + reset(); + } + if (self.lineHeight <= 0) { + textarea.style.overflowY = 'scroll'; + textarea.style.height = 'auto'; + textarea.rows = 3; + return; + } + var newHeight = 0, hasGrown = false; + + if ((textarea.scrollHeight - offset) > self.maxAllowedHeight) { + textarea.style.overflowY = 'scroll'; + newHeight = self.maxAllowedHeight; + } + else { + textarea.style.overflowY = 'hidden'; + textarea.style.height = 'auto'; + newHeight = textarea.scrollHeight/* - offset*/; + hasGrown = true; + } + textarea.style.height = newHeight + 'px'; } - var self = this; - void 0 === maxLines && (maxLines = 999), self.getOffset = function(textarea) { - for (var style = window.getComputedStyle(textarea, null), props = ["paddingTop", "paddingBottom"], offset = 0, i = 0; i < props.length; i++) offset += parseInt(style[props[i]]); - return offset - }; - var offset; - textarea.addEventListener("input", autogrowFn), textarea.addEventListener("focus", autogrowFn), textarea.addEventListener("valueset", autogrowFn), autogrowFn() + + // Call autogrowFn() when textarea's value is changed + textarea.addEventListener('input', autogrowFn); + textarea.addEventListener('focus', autogrowFn); + textarea.addEventListener('valueset', autogrowFn); + + autogrowFn(); } - var EmbyTextAreaPrototype = Object.create(HTMLTextAreaElement.prototype), - elementId = 0; + + var EmbyTextAreaPrototype = Object.create(HTMLTextAreaElement.prototype); + + var elementId = 0; + if (Object.getOwnPropertyDescriptor && Object.defineProperty) { - var descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value"); + + var descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value'); + + // descriptor returning null in webos if (descriptor && descriptor.configurable) { var baseSetMethod = descriptor.set; - descriptor.set = function(value) { - baseSetMethod.call(this, value), this.dispatchEvent(new CustomEvent("valueset", { - bubbles: !1, - cancelable: !1 - })) - }, Object.defineProperty(HTMLTextAreaElement.prototype, "value", descriptor) + descriptor.set = function (value) { + baseSetMethod.call(this, value); + + this.dispatchEvent(new CustomEvent('valueset', { + bubbles: false, + cancelable: false + })); + }; + + Object.defineProperty(HTMLTextAreaElement.prototype, 'value', descriptor); } } - EmbyTextAreaPrototype.createdCallback = function() { - this.id || (this.id = "embytextarea" + elementId, elementId++) - }, EmbyTextAreaPrototype.attachedCallback = function() { - if (!this.classList.contains("emby-textarea")) { - this.rows = 1, this.classList.add("emby-textarea"); - var parentNode = this.parentNode, - label = this.ownerDocument.createElement("label"); - label.innerHTML = this.getAttribute("label") || "", label.classList.add("textareaLabel"), label.htmlFor = this.id, parentNode.insertBefore(label, this), this.addEventListener("focus", function() { - label.classList.add("textareaLabelFocused"), label.classList.remove("textareaLabelUnfocused") - }), this.addEventListener("blur", function() { - label.classList.remove("textareaLabelFocused"), label.classList.add("textareaLabelUnfocused") - }), this.label = function(text) { - label.innerHTML = text - }, new autoGrow(this) + + EmbyTextAreaPrototype.createdCallback = function () { + + if (!this.id) { + this.id = 'embytextarea' + elementId; + elementId++; } - }, document.registerElement("emby-textarea", { + }; + + EmbyTextAreaPrototype.attachedCallback = function () { + + if (this.classList.contains('emby-textarea')) { + return; + } + + this.rows = 1; + this.classList.add('emby-textarea'); + + var parentNode = this.parentNode; + var label = this.ownerDocument.createElement('label'); + label.innerHTML = this.getAttribute('label') || ''; + label.classList.add('textareaLabel'); + + label.htmlFor = this.id; + parentNode.insertBefore(label, this); + + this.addEventListener('focus', function () { + label.classList.add('textareaLabelFocused'); + label.classList.remove('textareaLabelUnfocused'); + }); + this.addEventListener('blur', function () { + label.classList.remove('textareaLabelFocused'); + label.classList.add('textareaLabelUnfocused'); + }); + + this.label = function (text) { + label.innerHTML = text; + }; + + new autoGrow(this); + }; + + document.registerElement('emby-textarea', { prototype: EmbyTextAreaPrototype, - extends: "textarea" - }) + extends: 'textarea' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.css b/src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.css index c03115e976..a55f4efc6d 100644 --- a/src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.css +++ b/src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.css @@ -2,13 +2,8 @@ position: relative; z-index: 1; vertical-align: middle; - display: -webkit-inline-box; - display: -webkit-inline-flex; display: inline-flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-sizing: border-box; box-sizing: border-box; width: 100%; margin: 0; @@ -19,17 +14,12 @@ -moz-user-select: none; -ms-user-select: none; user-select: none; - -webkit-box-orient: horizontal; - -webkit-box-direction: reverse; - -webkit-flex-direction: row-reverse; flex-direction: row-reverse; - -webkit-box-pack: end; - -webkit-justify-content: flex-end; - justify-content: flex-end + justify-content: flex-end; } .toggleContainer { - margin-bottom: 1.8em + margin-bottom: 1.8em; } .mdl-switch__input { @@ -42,29 +32,28 @@ -moz-appearance: none; -webkit-appearance: none; appearance: none; - border: none + border: none; } .mdl-switch__trackContainer { position: relative; - width: 2.9em + width: 2.9em; } .mdl-switch__track { - background: rgba(0, 0, 0, .2); + background: rgba(0,0,0, 0.2); height: 1em; - -webkit-border-radius: 1em; border-radius: 1em; - cursor: pointer + cursor: pointer; } -.mdl-switch__input:checked+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__track { - background: rgba(0,164,220, .5) +.mdl-switch__input:checked + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__track { + background: rgba(82,181,75, 0.5); } -.mdl-switch__input[disabled]+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__track { - background: rgba(0, 0, 0, .12); - cursor: auto +.mdl-switch__input[disabled] + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__track { + background: rgba(0,0,0, 0.12); + cursor: auto; } .mdl-switch__thumb { @@ -74,41 +63,26 @@ top: -.25em; height: 1.44em; width: 1.44em; - -webkit-border-radius: 50%; border-radius: 50%; cursor: pointer; - -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12); - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12); - -webkit-transition-duration: .28s; - -o-transition-duration: .28s; - transition-duration: .28s; - -webkit-transition-timing-function: cubic-bezier(.4, 0, .2, 1); - -o-transition-timing-function: cubic-bezier(.4, 0, .2, 1); - transition-timing-function: cubic-bezier(.4, 0, .2, 1); - -webkit-transition-property: left; - -o-transition-property: left; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); + transition-duration: 0.28s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-property: left; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center + justify-content: center; } -.mdl-switch__input:checked+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__thumb { - background: #00a4dc; +.mdl-switch__input:checked + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__thumb { + background: rgb(82,181,75); left: 1.466em; - -webkit-box-shadow: 0 3px .28em 0 rgba(0, 0, 0, .14), 0 3px 3px -2px rgba(0, 0, 0, .2), 0 1px .56em 0 rgba(0, 0, 0, .12); - box-shadow: 0 3px .28em 0 rgba(0, 0, 0, .14), 0 3px 3px -2px rgba(0, 0, 0, .2), 0 1px .56em 0 rgba(0, 0, 0, .12) + box-shadow: 0 3px 0.28em 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.2), 0 1px .56em 0 rgba(0, 0, 0, 0.12); } -.mdl-switch__input[disabled]+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__thumb { - background: #bdbdbd; - cursor: auto +.mdl-switch__input[disabled] + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__thumb { + background: rgb(189,189,189); + cursor: auto; } .mdl-switch__focus-helper { @@ -118,38 +92,31 @@ -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); display: inline-block; - -webkit-box-sizing: border-box; box-sizing: border-box; width: .6em; height: .6em; - -webkit-border-radius: 50%; border-radius: 50%; - background-color: transparent + background-color: transparent; } -.mdl-switch__input:focus+.mdl-switch__label+.mdl-switch__trackContainer .mdl-switch__focus-helper { - -webkit-box-shadow: 0 0 0 1.39em rgba(0, 0, 0, .05); - box-shadow: 0 0 0 1.39em rgba(0, 0, 0, .05) +.mdl-switch__input:focus + .mdl-switch__label + .mdl-switch__trackContainer .mdl-switch__focus-helper { + box-shadow: 0 0 0 1.39em rgba(0, 0, 0, .05); } -.mdl-switch__input:checked:focus+.mdl-switch__label+.mdl-switch__trackContainer .mdl-switch__focus-helper { - -webkit-box-shadow: 0 0 0 1.39em rgba(0,164,220, .26); - box-shadow: 0 0 0 1.39em rgba(0,164,220, .26); - background-color: rgba(0,164,220, .26) +.mdl-switch__input:checked:focus + .mdl-switch__label + .mdl-switch__trackContainer .mdl-switch__focus-helper { + box-shadow: 0 0 0 1.39em rgba(82,181,75, 0.26); + background-color: rgba(82,181,75, 0.26); } .mdl-switch__label { cursor: pointer; - margin: 0 0 0 .7em; - display: -webkit-inline-box; - display: -webkit-inline-flex; + margin: 0; display: inline-flex; - -webkit-box-align: center; - -webkit-align-items: center; - align-items: center + align-items: center; + margin-left: .7em; } .mdl-switch__input[disabled] .mdl-switch__label { - color: #bdbdbd; - cursor: auto -} \ No newline at end of file + color: rgb(189,189,189); + cursor: auto; +} diff --git a/src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.js b/src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.js index f62899902d..d6d31957b2 100644 --- a/src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.js +++ b/src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.js @@ -1,22 +1,50 @@ -define(["css!./emby-toggle", "registerElement"], function() { - "use strict"; +define(['css!./emby-toggle', 'registerElement'], function () { + 'use strict'; + + var EmbyTogglePrototype = Object.create(HTMLInputElement.prototype); function onKeyDown(e) { - if (13 === e.keyCode) return e.preventDefault(), this.checked = !this.checked, this.dispatchEvent(new CustomEvent("change", { - bubbles: !0 - })), !1 - } - var EmbyTogglePrototype = Object.create(HTMLInputElement.prototype); - EmbyTogglePrototype.attachedCallback = function() { - if ("true" !== this.getAttribute("data-embytoggle")) { - this.setAttribute("data-embytoggle", "true"), this.classList.add("mdl-switch__input"); - var labelElement = this.parentNode; - labelElement.classList.add("mdl-switch"), labelElement.classList.add("mdl-js-switch"); - var labelTextElement = labelElement.querySelector("span"); - labelElement.insertAdjacentHTML("beforeend", '
'), labelTextElement.classList.add("toggleButtonLabel"), labelTextElement.classList.add("mdl-switch__label"), this.addEventListener("keydown", onKeyDown) + + // Don't submit form on enter + if (e.keyCode === 13) { + e.preventDefault(); + + this.checked = !this.checked; + + this.dispatchEvent(new CustomEvent('change', { + bubbles: true + })); + + return false; } - }, document.registerElement("emby-toggle", { + } + + EmbyTogglePrototype.attachedCallback = function () { + + if (this.getAttribute('data-embytoggle') === 'true') { + return; + } + + this.setAttribute('data-embytoggle', 'true'); + + this.classList.add('mdl-switch__input'); + + var labelElement = this.parentNode; + labelElement.classList.add('mdl-switch'); + labelElement.classList.add('mdl-js-switch'); + + var labelTextElement = labelElement.querySelector('span'); + + labelElement.insertAdjacentHTML('beforeend', '
'); + + labelTextElement.classList.add('toggleButtonLabel'); + labelTextElement.classList.add('mdl-switch__label'); + + this.addEventListener('keydown', onKeyDown); + }; + + document.registerElement('emby-toggle', { prototype: EmbyTogglePrototype, - extends: "input" - }) + extends: 'input' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/fetchhelper.js b/src/bower_components/emby-webcomponents/fetchhelper.js index ed0c74d6c4..64bd5159a5 100644 --- a/src/bower_components/emby-webcomponents/fetchhelper.js +++ b/src/bower_components/emby-webcomponents/fetchhelper.js @@ -1,54 +1,132 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; function getFetchPromise(request) { + var headers = request.headers || {}; - "json" === request.dataType && (headers.accept = "application/json"); + + if (request.dataType === 'json') { + headers.accept = 'application/json'; + } + var fetchRequest = { - headers: headers, - method: request.type, - credentials: "same-origin" - }, - contentType = request.contentType; - request.data && ("string" == typeof request.data ? fetchRequest.body = request.data : (fetchRequest.body = paramsToString(request.data), contentType = contentType || "application/x-www-form-urlencoded; charset=UTF-8")), contentType && (headers["Content-Type"] = contentType); + headers: headers, + method: request.type, + credentials: 'same-origin' + }; + + var contentType = request.contentType; + + if (request.data) { + + if (typeof request.data === 'string') { + fetchRequest.body = request.data; + } else { + fetchRequest.body = paramsToString(request.data); + + contentType = contentType || 'application/x-www-form-urlencoded; charset=UTF-8'; + } + } + + if (contentType) { + + headers['Content-Type'] = contentType; + } + var url = request.url; + if (request.query) { var paramString = paramsToString(request.query); - paramString && (url += "?" + paramString) + if (paramString) { + url += '?' + paramString; + } } - return request.timeout ? fetchWithTimeout(url, fetchRequest, request.timeout) : fetch(url, fetchRequest) + + if (!request.timeout) { + return fetch(url, fetchRequest); + } + + return fetchWithTimeout(url, fetchRequest, request.timeout); } function fetchWithTimeout(url, options, timeoutMs) { - return console.log("fetchWithTimeout: timeoutMs: " + timeoutMs + ", url: " + url), new Promise(function(resolve, reject) { + + console.log('fetchWithTimeout: timeoutMs: ' + timeoutMs + ', url: ' + url); + + return new Promise(function (resolve, reject) { + var timeout = setTimeout(reject, timeoutMs); - options = options || {}, options.credentials = "same-origin", fetch(url, options).then(function(response) { - clearTimeout(timeout), console.log("fetchWithTimeout: succeeded connecting to url: " + url), resolve(response) - }, function(error) { - clearTimeout(timeout), console.log("fetchWithTimeout: timed out connecting to url: " + url), reject() - }) - }) + + options = options || {}; + options.credentials = 'same-origin'; + + fetch(url, options).then(function (response) { + clearTimeout(timeout); + + console.log('fetchWithTimeout: succeeded connecting to url: ' + url); + + resolve(response); + }, function (error) { + + clearTimeout(timeout); + + console.log('fetchWithTimeout: timed out connecting to url: ' + url); + + reject(); + }); + }); } function paramsToString(params) { + var values = []; + for (var key in params) { + var value = params[key]; - null !== value && void 0 !== value && "" !== value && values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value)) + + if (value !== null && value !== undefined && value !== '') { + values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value)); + } } - return values.join("&") + return values.join('&'); } function ajax(request) { - if (!request) throw new Error("Request cannot be null"); - return request.headers = request.headers || {}, console.log("requesting url: " + request.url), getFetchPromise(request).then(function(response) { - return console.log("response status: " + response.status + ", url: " + request.url), response.status < 400 ? "json" === request.dataType || "application/json" === request.headers.accept ? response.json() : "text" === request.dataType || 0 === (response.headers.get("Content-Type") || "").toLowerCase().indexOf("text/") ? response.text() : response : Promise.reject(response) - }, function(err) { - throw console.log("request failed to url: " + request.url), err - }) + + if (!request) { + throw new Error("Request cannot be null"); + } + + request.headers = request.headers || {}; + + console.log('requesting url: ' + request.url); + + return getFetchPromise(request).then(function (response) { + + console.log('response status: ' + response.status + ', url: ' + request.url); + + if (response.status < 400) { + + if (request.dataType === 'json' || request.headers.accept === 'application/json') { + return response.json(); + } else if (request.dataType === 'text' || (response.headers.get('Content-Type') || '').toLowerCase().indexOf('text/') === 0) { + return response.text(); + } else { + return response; + } + } else { + return Promise.reject(response); + } + + }, function (err) { + + console.log('request failed to url: ' + request.url); + throw err; + }); } return { getFetchPromise: getFetchPromise, ajax: ajax - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/filedownloader.js b/src/bower_components/emby-webcomponents/filedownloader.js index ea7a1ff99f..ebd004da68 100644 --- a/src/bower_components/emby-webcomponents/filedownloader.js +++ b/src/bower_components/emby-webcomponents/filedownloader.js @@ -1,10 +1,12 @@ -define(["multi-download"], function(multiDownload) { - "use strict"; +define(['multi-download'], function (multiDownload) { + 'use strict'; + return { - download: function(items) { - multiDownload(items.map(function(item) { - return item.url - })) + download: function (items) { + + multiDownload(items.map(function (item) { + return item.url; + })); } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/filesystem.js b/src/bower_components/emby-webcomponents/filesystem.js index 7f9599cc14..4489d2921f 100644 --- a/src/bower_components/emby-webcomponents/filesystem.js +++ b/src/bower_components/emby-webcomponents/filesystem.js @@ -1,11 +1,12 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; + return { - fileExists: function(path) { - return Promise.reject() + fileExists: function (path) { + return Promise.reject(); }, - directoryExists: function(path) { - return Promise.reject() + directoryExists: function (path) { + return Promise.reject(); } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/filtermenu/filtermenu.js b/src/bower_components/emby-webcomponents/filtermenu/filtermenu.js index e0fe446ebe..e405cc0943 100644 --- a/src/bower_components/emby-webcomponents/filtermenu/filtermenu.js +++ b/src/bower_components/emby-webcomponents/filtermenu/filtermenu.js @@ -1,125 +1,348 @@ -define(["require", "dom", "focusManager", "dialogHelper", "loading", "apphost", "inputManager", "layoutManager", "connectionManager", "appRouter", "globalize", "userSettings", "emby-checkbox", "emby-input", "paper-icon-button-light", "emby-select", "material-icons", "css!./../formdialog", "emby-button", "emby-linkbutton", "flexStyles"], function(require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) { - "use strict"; +define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost', 'inputManager', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) { + 'use strict'; function onSubmit(e) { - return e.preventDefault(), !1 + + e.preventDefault(); + return false; } function renderOptions(context, selector, cssClass, items, isCheckedFn) { + var elem = context.querySelector(selector); - items.length ? elem.classList.remove("hide") : elem.classList.add("hide"); - var html = ""; - html += items.map(function(filter) { - var itemHtml = "", - checkedHtml = isCheckedFn(filter) ? " checked" : ""; - return itemHtml += "" - }).join(""), elem.querySelector(".filterOptions").innerHTML = html + + if (items.length) { + + elem.classList.remove('hide'); + + } else { + elem.classList.add('hide'); + } + + var html = ''; + + html += items.map(function (filter) { + + var itemHtml = ''; + + var checkedHtml = isCheckedFn(filter) ? ' checked' : ''; + itemHtml += ''; + + return itemHtml; + + }).join(''); + + elem.querySelector('.filterOptions').innerHTML = html; } function renderDynamicFilters(context, result, options) { - renderOptions(context, ".genreFilters", "chkGenreFilter", result.Genres, function(i) { - var delimeter = -1 === (options.settings.GenreIds || "").indexOf("|") ? "," : "|"; - return -1 !== (delimeter + (options.settings.GenreIds || "") + delimeter).indexOf(delimeter + i.Id + delimeter) - }) + + // If there's a huge number of these they will be really show to render + //if (result.Tags) { + // result.Tags.length = Math.min(result.Tags.length, 50); + //} + + renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) { + + // Switching from | to , + var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|'; + return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1; + }); + + //renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) { + // var delimeter = '|'; + // return (delimeter + (query.OfficialRatings || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; + //}); + + //renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) { + // var delimeter = '|'; + // return (delimeter + (query.Tags || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; + //}); + + //renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) { + + // var delimeter = ','; + // return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; + //}); } function loadDynamicFilters(context, options) { - var apiClient = connectionManager.getApiClient(options.serverId), - filterMenuOptions = Object.assign(options.filterMenuOptions, { - UserId: apiClient.getCurrentUserId(), - ParentId: options.parentId, - IncludeItemTypes: options.itemTypes.join(",") - }); - apiClient.getFilters(filterMenuOptions).then(function(result) { - renderDynamicFilters(context, result, options) - }, function() {}) + + var apiClient = connectionManager.getApiClient(options.serverId); + + var filterMenuOptions = Object.assign(options.filterMenuOptions, { + + UserId: apiClient.getCurrentUserId(), + ParentId: options.parentId, + IncludeItemTypes: options.itemTypes.join(',') + }); + + apiClient.getFilters(filterMenuOptions).then(function (result) { + + renderDynamicFilters(context, result, options); + }, function () { + + // older server + }); } function initEditor(context, settings) { - context.querySelector("form").addEventListener("submit", onSubmit); - var i, length, elems = context.querySelectorAll(".simpleFilter"); - for (i = 0, length = elems.length; i < length; i++) "INPUT" === elems[i].tagName ? elems[i].checked = settings[elems[i].getAttribute("data-settingname")] || !1 : elems[i].querySelector("input").checked = settings[elems[i].getAttribute("data-settingname")] || !1; - var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(",") : []; - for (elems = context.querySelectorAll(".chkVideoTypeFilter"), i = 0, length = elems.length; i < length; i++) elems[i].checked = -1 !== videoTypes.indexOf(elems[i].getAttribute("data-filter")); - var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(",") : []; - for (elems = context.querySelectorAll(".chkSeriesStatus"), i = 0, length = elems.length; i < length; i++) elems[i].checked = -1 !== seriesStatuses.indexOf(elems[i].getAttribute("data-filter")); - context.querySelector(".basicFilterSection .viewSetting:not(.hide)") ? context.querySelector(".basicFilterSection").classList.remove("hide") : context.querySelector(".basicFilterSection").classList.add("hide"), context.querySelector(".featureSection .viewSetting:not(.hide)") ? context.querySelector(".featureSection").classList.remove("hide") : context.querySelector(".featureSection").classList.add("hide") + + context.querySelector('form').addEventListener('submit', onSubmit); + + var elems = context.querySelectorAll('.simpleFilter'); + var i, length; + + for (i = 0, length = elems.length; i < length; i++) { + + if (elems[i].tagName === 'INPUT') { + elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false; + } else { + elems[i].querySelector('input').checked = settings[elems[i].getAttribute('data-settingname')] || false; + } + } + + var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : []; + elems = context.querySelectorAll('.chkVideoTypeFilter'); + + for (i = 0, length = elems.length; i < length; i++) { + + elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1; + } + + var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : []; + elems = context.querySelectorAll('.chkSeriesStatus'); + + for (i = 0, length = elems.length; i < length; i++) { + + elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1; + } + + if (context.querySelector('.basicFilterSection .viewSetting:not(.hide)')) { + context.querySelector('.basicFilterSection').classList.remove('hide'); + } else { + context.querySelector('.basicFilterSection').classList.add('hide'); + } + + if (context.querySelector('.featureSection .viewSetting:not(.hide)')) { + context.querySelector('.featureSection').classList.remove('hide'); + } else { + context.querySelector('.featureSection').classList.add('hide'); + } } function saveValues(context, settings, settingsKey) { - var i, length, elems = context.querySelectorAll(".simpleFilter"); - for (i = 0, length = elems.length; i < length; i++) "INPUT" === elems[i].tagName ? setBasicFilter(context, settingsKey + "-filter-" + elems[i].getAttribute("data-settingname"), elems[i]) : setBasicFilter(context, settingsKey + "-filter-" + elems[i].getAttribute("data-settingname"), elems[i].querySelector("input")); + + var elems = context.querySelectorAll('.simpleFilter'); + var i, length; + for (i = 0, length = elems.length; i < length; i++) { + + if (elems[i].tagName === 'INPUT') { + setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]); + } else { + setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i].querySelector('input')); + } + } + + // Video type var videoTypes = []; - for (elems = context.querySelectorAll(".chkVideoTypeFilter"), i = 0, length = elems.length; i < length; i++) elems[i].checked && videoTypes.push(elems[i].getAttribute("data-filter")); - userSettings.setFilter(settingsKey + "-filter-VideoTypes", videoTypes.join(",")); + elems = context.querySelectorAll('.chkVideoTypeFilter'); + + for (i = 0, length = elems.length; i < length; i++) { + + if (elems[i].checked) { + videoTypes.push(elems[i].getAttribute('data-filter')); + } + } + userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(',')); + + // Series status var seriesStatuses = []; - for (elems = context.querySelectorAll(".chkSeriesStatus"), i = 0, length = elems.length; i < length; i++) elems[i].checked && seriesStatuses.push(elems[i].getAttribute("data-filter")); + elems = context.querySelectorAll('.chkSeriesStatus'); + + for (i = 0, length = elems.length; i < length; i++) { + + if (elems[i].checked) { + seriesStatuses.push(elems[i].getAttribute('data-filter')); + } + } + + // Genres var genres = []; - for (elems = context.querySelectorAll(".chkGenreFilter"), i = 0, length = elems.length; i < length; i++) elems[i].checked && genres.push(elems[i].getAttribute("data-filter")); - userSettings.setFilter(settingsKey + "-filter-GenreIds", genres.join(",")) + elems = context.querySelectorAll('.chkGenreFilter'); + + for (i = 0, length = elems.length; i < length; i++) { + + if (elems[i].checked) { + genres.push(elems[i].getAttribute('data-filter')); + } + } + userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(',')); } function setBasicFilter(context, key, elem) { + var value = elem.checked; - value = value || null, userSettings.setFilter(key, value) + value = value ? value : null; + userSettings.setFilter(key, value); } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function moveCheckboxFocus(elem, offset) { - for (var parent = dom.parentWithClass(elem, "checkboxList-verticalwrap"), elems = focusManager.getFocusableElements(parent), index = -1, i = 0, length = elems.length; i < length; i++) + + var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap'); + var elems = focusManager.getFocusableElements(parent); + + var index = -1; + for (var i = 0, length = elems.length; i < length; i++) { if (elems[i] === elem) { index = i; - break - } index += offset, index = Math.min(elems.length - 1, index), index = Math.max(0, index); + break; + } + } + + index += offset; + + index = Math.min(elems.length - 1, index); + index = Math.max(0, index); + var newElem = elems[index]; - newElem && focusManager.focus(newElem) + if (newElem) { + focusManager.focus(newElem); + } } function onInputCommand(e) { switch (e.detail.command) { - case "left": - moveCheckboxFocus(e.target, -1), e.preventDefault(); + + case 'left': + moveCheckboxFocus(e.target, -1); + e.preventDefault(); + break; + case 'right': + moveCheckboxFocus(e.target, 1); + e.preventDefault(); + break; + default: break; - case "right": - moveCheckboxFocus(e.target, 1), e.preventDefault() } } - function FilterMenu() {} + function FilterMenu() { + + } function bindCheckboxInput(context, on) { - for (var elems = context.querySelectorAll(".checkboxList-verticalwrap"), i = 0, length = elems.length; i < length; i++) on ? inputManager.on(elems[i], onInputCommand) : inputManager.off(elems[i], onInputCommand) + + var elems = context.querySelectorAll('.checkboxList-verticalwrap'); + for (var i = 0, length = elems.length; i < length; i++) { + if (on) { + inputManager.on(elems[i], onInputCommand); + } else { + inputManager.off(elems[i], onInputCommand); + } + } } - return FilterMenu.prototype.show = function(options) { - return new Promise(function(resolve, reject) { - require(["text!./filtermenu.template.html"], function(template) { + + FilterMenu.prototype.show = function (options) { + + return new Promise(function (resolve, reject) { + + require(['text!./filtermenu.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'small'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - var html = ""; - html += '
', html += '', html += '

${Filters}

', html += "
", html += template, dlg.innerHTML = globalize.translateDocument(html, "sharedcomponents"); - for (var settingElements = dlg.querySelectorAll(".viewSetting"), i = 0, length = settingElements.length; i < length; i++) - 1 === options.visibleSettings.indexOf(settingElements[i].getAttribute("data-settingname")) ? settingElements[i].classList.add("hide") : settingElements[i].classList.remove("hide"); - initEditor(dlg, options.settings), loadDynamicFilters(dlg, options), bindCheckboxInput(dlg, !0), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0); + + dlg.classList.add('formDialog'); + + var html = ''; + + html += '
'; + html += ''; + html += '

${Filters}

'; + + html += '
'; + + html += template; + + dlg.innerHTML = globalize.translateDocument(html, 'sharedcomponents'); + + var settingElements = dlg.querySelectorAll('.viewSetting'); + for (var i = 0, length = settingElements.length; i < length; i++) { + if (options.visibleSettings.indexOf(settingElements[i].getAttribute('data-settingname')) === -1) { + settingElements[i].classList.add('hide'); + } else { + settingElements[i].classList.remove('hide'); + } + } + + initEditor(dlg, options.settings); + loadDynamicFilters(dlg, options); + + bindCheckboxInput(dlg, true); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + var submitted; - dlg.querySelector("form").addEventListener("change", function() { - submitted = !0 - }, !0), dialogHelper.open(dlg).then(function() { - if (bindCheckboxInput(dlg, !1), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), submitted) return saveValues(dlg, options.settings, options.settingsKey), void resolve(); - reject() - }) - }) - }) - }, FilterMenu + + dlg.querySelector('form').addEventListener('change', function () { + + submitted = true; + //if (options.onChange) { + // saveValues(dlg, options.settings, options.settingsKey); + // options.onChange(); + //} + + }, true); + + dialogHelper.open(dlg).then(function () { + + bindCheckboxInput(dlg, false); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + if (submitted) { + + //if (!options.onChange) { + saveValues(dlg, options.settings, options.settingsKey); + resolve(); + //} + return; + } + + reject(); + }); + }); + }); + }; + + return FilterMenu; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/flexstyles.css b/src/bower_components/emby-webcomponents/flexstyles.css index b801609a6f..b35e25d57b 100644 --- a/src/bower_components/emby-webcomponents/flexstyles.css +++ b/src/bower_components/emby-webcomponents/flexstyles.css @@ -1,70 +1,47 @@ .flex { - display: -webkit-box; - display: -webkit-flex; - display: flex + display: flex; } .inline-flex { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: inline-flex + display: inline-flex; } .flex-direction-column { - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - flex-direction: column + flex-direction: column; } .flex-direction-row { - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -webkit-flex-direction: row; - flex-direction: row + flex-direction: row; } .flex-grow { - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - flex-grow: 1 + flex-grow: 1; } .flex-shrink-zero { - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } .align-items-center { - -webkit-box-align: center; - -webkit-align-items: center; - align-items: center + align-items: center; } .align-items-flex-start { - -webkit-box-align: start; - -webkit-align-items: flex-start; - align-items: flex-start + align-items: flex-start; } .justify-content-center { - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center + justify-content: center; } .justify-content-flex-end { - -webkit-box-pack: end; - -webkit-justify-content: flex-end; - justify-content: flex-end + justify-content: flex-end; } .flex-wrap-wrap { - -webkit-flex-wrap: wrap; - flex-wrap: wrap + flex-wrap: wrap; } .align-self-flex-end { - -webkit-align-self: flex-end; - align-self: flex-end + align-self: flex-end; } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/flvjs/flv.min.js b/src/bower_components/emby-webcomponents/flvjs/flv.min.js index bc71e64626..4a3efed93f 100644 --- a/src/bower_components/emby-webcomponents/flvjs/flv.min.js +++ b/src/bower_components/emby-webcomponents/flvjs/flv.min.js @@ -1,6277 +1,7 @@ -! function(e) { - if ("object" == typeof exports && "undefined" != typeof module) module.exports = e(); - else if ("function" == typeof define && define.amd) define([], e); - else { - var t; - t = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : this, t.flvjs = e() - } -}(function() { - var e; - return function e(t, n, i) { - function r(a, o) { - if (!n[a]) { - if (!t[a]) { - var u = "function" == typeof require && require; - if (!o && u) return u(a, !0); - if (s) return s(a, !0); - var l = new Error("Cannot find module '" + a + "'"); - throw l.code = "MODULE_NOT_FOUND", l - } - var d = n[a] = { - exports: {} - }; - t[a][0].call(d.exports, function(e) { - var n = t[a][1][e]; - return r(n || e) - }, d, d.exports, e, t, n, i) - } - return n[a].exports - } - for (var s = "function" == typeof require && require, a = 0; a < i.length; a++) r(i[a]); - return r - }({ - 1: [function(t, n, i) { - (function(r, s) { - ! function(t, r) { - "object" == typeof i && void 0 !== n ? n.exports = r() : "function" == typeof e && e.amd ? e(r) : t.ES6Promise = r() - }(this, function() { - "use strict"; - - function e(e) { - return "function" == typeof e || "object" == typeof e && null !== e - } - - function n(e) { - return "function" == typeof e - } - - function i(e) { - K = e - } - - function a(e) { - q = e - } - - function o() { - return void 0 !== H ? function() { - H(l) - } : u() - } - - function u() { - var e = setTimeout; - return function() { - return e(l, 1) - } - } - - function l() { - for (var e = 0; e < z; e += 2) { - (0, J[e])(J[e + 1]), J[e] = void 0, J[e + 1] = void 0 - } - z = 0 - } - - function d(e, t) { - var n = arguments, - i = this, - r = new this.constructor(f); - void 0 === r[ee] && I(r); - var s = i._state; - return s ? function() { - var e = n[s - 1]; - q(function() { - return O(s, r, e, i._result) - }) - }() : L(i, r, e, t), r - } - - function h(e) { - var t = this; - if (e && "object" == typeof e && e.constructor === t) return e; - var n = new t(f); - return E(n, e), n - } - - function f() {} - - function c() { - return new TypeError("You cannot resolve a promise with itself") - } - - function _() { - return new TypeError("A promises callback cannot return that same promise.") - } - - function m(e) { - try { - return e.then - } catch (e) { - return re.error = e, re - } - } - - function p(e, t, n, i) { - try { - e.call(t, n, i) - } catch (e) { - return e - } - } - - function v(e, t, n) { - q(function(e) { - var i = !1, - r = p(n, t, function(n) { - i || (i = !0, t !== n ? E(e, n) : S(e, n)) - }, function(t) { - i || (i = !0, k(e, t)) - }, "Settle: " + (e._label || " unknown promise")); - !i && r && (i = !0, k(e, r)) - }, e) - } - - function g(e, t) { - t._state === ne ? S(e, t._result) : t._state === ie ? k(e, t._result) : L(t, void 0, function(t) { - return E(e, t) - }, function(t) { - return k(e, t) - }) - } - - function y(e, t, i) { - t.constructor === e.constructor && i === d && t.constructor.resolve === h ? g(e, t) : i === re ? (k(e, re.error), re.error = null) : void 0 === i ? S(e, t) : n(i) ? v(e, t, i) : S(e, t) - } - - function E(t, n) { - t === n ? k(t, c()) : e(n) ? y(t, n, m(n)) : S(t, n) - } - - function b(e) { - e._onerror && e._onerror(e._result), w(e) - } - - function S(e, t) { - e._state === te && (e._result = t, e._state = ne, 0 !== e._subscribers.length && q(w, e)) - } - - function k(e, t) { - e._state === te && (e._state = ie, e._result = t, q(b, e)) - } - - function L(e, t, n, i) { - var r = e._subscribers, - s = r.length; - e._onerror = null, r[s] = t, r[s + ne] = n, r[s + ie] = i, 0 === s && e._state && q(w, e) - } - - function w(e) { - var t = e._subscribers, - n = e._state; - if (0 !== t.length) { - for (var i = void 0, r = void 0, s = e._result, a = 0; a < t.length; a += 3) i = t[a], r = t[a + n], i ? O(n, i, r, s) : r(s); - e._subscribers.length = 0 - } - } - - function R() { - this.error = null - } - - function A(e, t) { - try { - return e(t) - } catch (e) { - return se.error = e, se - } - } - - function O(e, t, i, r) { - var s = n(i), - a = void 0, - o = void 0, - u = void 0, - l = void 0; - if (s) { - if (a = A(i, r), a === se ? (l = !0, o = a.error, a.error = null) : u = !0, t === a) return void k(t, _()) - } else a = r, u = !0; - t._state !== te || (s && u ? E(t, a) : l ? k(t, o) : e === ne ? S(t, a) : e === ie && k(t, a)) - } - - function T(e, t) { - try { - t(function(t) { - E(e, t) - }, function(t) { - k(e, t) - }) - } catch (t) { - k(e, t) - } - } - - function C() { - return ae++ - } - - function I(e) { - e[ee] = ae++, e._state = void 0, e._result = void 0, e._subscribers = [] - } - - function x(e, t) { - this._instanceConstructor = e, this.promise = new e(f), this.promise[ee] || I(this.promise), V(t) ? (this._input = t, this.length = t.length, this._remaining = t.length, this._result = new Array(this.length), 0 === this.length ? S(this.promise, this._result) : (this.length = this.length || 0, this._enumerate(), 0 === this._remaining && S(this.promise, this._result))) : k(this.promise, M()) - } - - function M() { - return new Error("Array Methods must be provided an Array") - } - - function D(e) { - return new x(this, e).promise - } - - function B(e) { - var t = this; - return new t(V(e) ? function(n, i) { - for (var r = e.length, s = 0; s < r; s++) t.resolve(e[s]).then(n, i) - } : function(e, t) { - return t(new TypeError("You must pass an array to race.")) - }) - } - - function j(e) { - var t = this, - n = new t(f); - return k(n, e), n - } - - function P() { - throw new TypeError("You must pass a resolver function as the first argument to the promise constructor") - } - - function U() { - throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.") - } - - function N(e) { - this[ee] = C(), this._result = this._state = void 0, this._subscribers = [], f !== e && ("function" != typeof e && P(), this instanceof N ? T(this, e) : U()) - } - - function F() { - var e = void 0; - if (void 0 !== s) e = s; - else if ("undefined" != typeof self) e = self; - else try { - e = Function("return this")() - } catch (e) { - throw new Error("polyfill failed because global object is unavailable in this environment") - } - var t = e.Promise; - if (t) { - var n = null; - try { - n = Object.prototype.toString.call(t.resolve()) - } catch (e) {} - if ("[object Promise]" === n && !t.cast) return - } - e.Promise = N - } - var G = void 0; - G = Array.isArray ? Array.isArray : function(e) { - return "[object Array]" === Object.prototype.toString.call(e) - }; - var V = G, - z = 0, - H = void 0, - K = void 0, - q = function(e, t) { - J[z] = e, J[z + 1] = t, 2 === (z += 2) && (K ? K(l) : $()) - }, - W = "undefined" != typeof window ? window : void 0, - X = W || {}, - Y = X.MutationObserver || X.WebKitMutationObserver, - Z = "undefined" == typeof self && void 0 !== r && "[object process]" === {}.toString.call(r), - Q = "undefined" != typeof Uint8ClampedArray && "undefined" != typeof importScripts && "undefined" != typeof MessageChannel, - J = new Array(1e3), - $ = void 0; - $ = Z ? function() { - return function() { - return r.nextTick(l) - } - }() : Y ? function() { - var e = 0, - t = new Y(l), - n = document.createTextNode(""); - return t.observe(n, { - characterData: !0 - }), - function() { - n.data = e = ++e % 2 - } - }() : Q ? function() { - var e = new MessageChannel; - return e.port1.onmessage = l, - function() { - return e.port2.postMessage(0) - } - }() : void 0 === W && "function" == typeof t ? function() { - try { - var e = t, - n = e("vertx"); - return H = n.runOnLoop || n.runOnContext, o() - } catch (e) { - return u() - } - }() : u(); - var ee = Math.random().toString(36).substring(16), - te = void 0, - ne = 1, - ie = 2, - re = new R, - se = new R, - ae = 0; - return x.prototype._enumerate = function() { - for (var e = this.length, t = this._input, n = 0; this._state === te && n < e; n++) this._eachEntry(t[n], n) - }, x.prototype._eachEntry = function(e, t) { - var n = this._instanceConstructor, - i = n.resolve; - if (i === h) { - var r = m(e); - if (r === d && e._state !== te) this._settledAt(e._state, t, e._result); - else if ("function" != typeof r) this._remaining--, this._result[t] = e; - else if (n === N) { - var s = new n(f); - y(s, e, r), this._willSettleAt(s, t) - } else this._willSettleAt(new n(function(t) { - return t(e) - }), t) - } else this._willSettleAt(i(e), t) - }, x.prototype._settledAt = function(e, t, n) { - var i = this.promise; - i._state === te && (this._remaining--, e === ie ? k(i, n) : this._result[t] = n), 0 === this._remaining && S(i, this._result) - }, x.prototype._willSettleAt = function(e, t) { - var n = this; - L(e, void 0, function(e) { - return n._settledAt(ne, t, e) - }, function(e) { - return n._settledAt(ie, t, e) - }) - }, N.all = D, N.race = B, N.resolve = h, N.reject = j, N._setScheduler = i, N._setAsap = a, N._asap = q, N.prototype = { - constructor: N, - then: d, - catch: function(e) { - return this.then(null, e) - } - }, N.polyfill = F, N.Promise = N, N - }) - }).call(this, t("_process"), "undefined" != typeof global ? global : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {}) - }, { - _process: 3 - }], - 2: [function(e, t, n) { - function i() { - this._events = this._events || {}, this._maxListeners = this._maxListeners || void 0 - } - - function r(e) { - return "function" == typeof e - } - - function s(e) { - return "number" == typeof e - } - - function a(e) { - return "object" == typeof e && null !== e - } - - function o(e) { - return void 0 === e - } - t.exports = i, i.EventEmitter = i, i.prototype._events = void 0, i.prototype._maxListeners = void 0, i.defaultMaxListeners = 10, i.prototype.setMaxListeners = function(e) { - if (!s(e) || e < 0 || isNaN(e)) throw TypeError("n must be a positive number"); - return this._maxListeners = e, this - }, i.prototype.emit = function(e) { - var t, n, i, s, u, l; - if (this._events || (this._events = {}), "error" === e && (!this._events.error || a(this._events.error) && !this._events.error.length)) { - if ((t = arguments[1]) instanceof Error) throw t; - var d = new Error('Uncaught, unspecified "error" event. (' + t + ")"); - throw d.context = t, d - } - if (n = this._events[e], o(n)) return !1; - if (r(n)) switch (arguments.length) { - case 1: - n.call(this); - break; - case 2: - n.call(this, arguments[1]); - break; - case 3: - n.call(this, arguments[1], arguments[2]); - break; - default: - s = Array.prototype.slice.call(arguments, 1), n.apply(this, s) - } else if (a(n)) - for (s = Array.prototype.slice.call(arguments, 1), l = n.slice(), i = l.length, u = 0; u < i; u++) l[u].apply(this, s); - return !0 - }, i.prototype.addListener = function(e, t) { - var n; - if (!r(t)) throw TypeError("listener must be a function"); - return this._events || (this._events = {}), this._events.newListener && this.emit("newListener", e, r(t.listener) ? t.listener : t), this._events[e] ? a(this._events[e]) ? this._events[e].push(t) : this._events[e] = [this._events[e], t] : this._events[e] = t, a(this._events[e]) && !this._events[e].warned && (n = o(this._maxListeners) ? i.defaultMaxListeners : this._maxListeners) && n > 0 && this._events[e].length > n && (this._events[e].warned = !0, console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.", this._events[e].length), "function" == typeof console.trace && console.trace()), this - }, i.prototype.on = i.prototype.addListener, i.prototype.once = function(e, t) { - function n() { - this.removeListener(e, n), i || (i = !0, t.apply(this, arguments)) - } - if (!r(t)) throw TypeError("listener must be a function"); - var i = !1; - return n.listener = t, this.on(e, n), this - }, i.prototype.removeListener = function(e, t) { - var n, i, s, o; - if (!r(t)) throw TypeError("listener must be a function"); - if (!this._events || !this._events[e]) return this; - if (n = this._events[e], s = n.length, i = -1, n === t || r(n.listener) && n.listener === t) delete this._events[e], this._events.removeListener && this.emit("removeListener", e, t); - else if (a(n)) { - for (o = s; o-- > 0;) - if (n[o] === t || n[o].listener && n[o].listener === t) { - i = o; - break - } if (i < 0) return this; - 1 === n.length ? (n.length = 0, delete this._events[e]) : n.splice(i, 1), this._events.removeListener && this.emit("removeListener", e, t) - } - return this - }, i.prototype.removeAllListeners = function(e) { - var t, n; - if (!this._events) return this; - if (!this._events.removeListener) return 0 === arguments.length ? this._events = {} : this._events[e] && delete this._events[e], this; - if (0 === arguments.length) { - for (t in this._events) "removeListener" !== t && this.removeAllListeners(t); - return this.removeAllListeners("removeListener"), this._events = {}, this - } - if (n = this._events[e], r(n)) this.removeListener(e, n); - else if (n) - for (; n.length;) this.removeListener(e, n[n.length - 1]); - return delete this._events[e], this - }, i.prototype.listeners = function(e) { - return this._events && this._events[e] ? r(this._events[e]) ? [this._events[e]] : this._events[e].slice() : [] - }, i.prototype.listenerCount = function(e) { - if (this._events) { - var t = this._events[e]; - if (r(t)) return 1; - if (t) return t.length - } - return 0 - }, i.listenerCount = function(e, t) { - return e.listenerCount(t) - } - }, {}], - 3: [function(e, t, n) { - function i() { - throw new Error("setTimeout has not been defined") - } - - function r() { - throw new Error("clearTimeout has not been defined") - } - - function s(e) { - if (h === setTimeout) return setTimeout(e, 0); - if ((h === i || !h) && setTimeout) return h = setTimeout, setTimeout(e, 0); - try { - return h(e, 0) - } catch (t) { - try { - return h.call(null, e, 0) - } catch (t) { - return h.call(this, e, 0) - } - } - } - - function a(e) { - if (f === clearTimeout) return clearTimeout(e); - if ((f === r || !f) && clearTimeout) return f = clearTimeout, clearTimeout(e); - try { - return f(e) - } catch (t) { - try { - return f.call(null, e) - } catch (t) { - return f.call(this, e) - } - } - } - - function o() { - p && _ && (p = !1, _.length ? m = _.concat(m) : v = -1, m.length && u()) - } - - function u() { - if (!p) { - var e = s(o); - p = !0; - for (var t = m.length; t;) { - for (_ = m, m = []; ++v < t;) _ && _[v].run(); - v = -1, t = m.length - } - _ = null, p = !1, a(e) - } - } - - function l(e, t) { - this.fun = e, this.array = t - } - - function d() {} - var h, f, c = t.exports = {}; - ! function() { - try { - h = "function" == typeof setTimeout ? setTimeout : i - } catch (e) { - h = i - } - try { - f = "function" == typeof clearTimeout ? clearTimeout : r - } catch (e) { - f = r - } - }(); - var _, m = [], - p = !1, - v = -1; - c.nextTick = function(e) { - var t = new Array(arguments.length - 1); - if (arguments.length > 1) - for (var n = 1; n < arguments.length; n++) t[n - 1] = arguments[n]; - m.push(new l(e, t)), 1 !== m.length || p || s(u) - }, l.prototype.run = function() { - this.fun.apply(null, this.array) - }, c.title = "browser", c.browser = !0, c.env = {}, c.argv = [], c.version = "", c.versions = {}, c.on = d, c.addListener = d, c.once = d, c.off = d, c.removeListener = d, c.removeAllListeners = d, c.emit = d, c.prependListener = d, c.prependOnceListener = d, c.listeners = function(e) { - return [] - }, c.binding = function(e) { - throw new Error("process.binding is not supported") - }, c.cwd = function() { - return "/" - }, c.chdir = function(e) { - throw new Error("process.chdir is not supported") - }, c.umask = function() { - return 0 - } - }, {}], - 4: [function(e, t, n) { - var i = arguments[3], - r = arguments[4], - s = arguments[5], - a = JSON.stringify; - t.exports = function(e, t) { - function n(e) { - p[e] = !0; - for (var t in r[e][1]) { - var i = r[e][1][t]; - p[i] || n(i) - } - } - for (var o, u = Object.keys(s), l = 0, d = u.length; l < d; l++) { - var h = u[l], - f = s[h].exports; - if (f === e || f && f.default === e) { - o = h; - break - } - } - if (!o) { - o = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); - for (var c = {}, l = 0, d = u.length; l < d; l++) { - var h = u[l]; - c[h] = h - } - r[o] = [Function(["require", "module", "exports"], "(" + e + ")(self)"), c] - } - var _ = Math.floor(Math.pow(16, 8) * Math.random()).toString(16), - m = {}; - m[o] = o, r[_] = [Function(["require"], "var f = require(" + a(o) + ");(f.default ? f.default : f)(self);"), m]; - var p = {}; - n(_); - var v = "(" + i + ")({" + Object.keys(p).map(function(e) { - return a(e) + ":[" + r[e][0] + "," + a(r[e][1]) + "]" - }).join(",") + "},{},[" + a(_) + "])", - g = window.URL || window.webkitURL || window.mozURL || window.msURL, - y = new Blob([v], { - type: "text/javascript" - }); - if (t && t.bare) return y; - var E = g.createObjectURL(y), - b = new Worker(E); - return b.objectURL = E, b - } - }, {}], - 5: [function(e, t, n) { - "use strict"; - - function i() { - return Object.assign({}, r) - } - Object.defineProperty(n, "__esModule", { - value: !0 - }), n.createDefaultConfig = i; - var r = n.defaultConfig = { - enableWorker: !1, - enableStashBuffer: !0, - stashInitialSize: void 0, - isLive: !1, - lazyLoad: !0, - lazyLoadMaxDuration: 180, - lazyLoadRecoverDuration: 30, - deferLoadAfterSourceOpen: !0, - autoCleanupMaxBackwardDuration: 180, - autoCleanupMinBackwardDuration: 120, - statisticsInfoReportInterval: 600, - fixAudioTimestampGap: !0, - accurateSeek: !1, - seekType: "range", - seekParamStart: "bstart", - seekParamEnd: "bend", - rangeLoadZeroStart: !1, - customSeekHandler: void 0, - reuseRedirectedURL: !1 - } - }, {}], - 6: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = e("../io/io-controller.js"), - a = function(e) { - return e && e.__esModule ? e : { - default: e - } - }(s), - o = e("../config.js"), - u = function() { - function e() { - i(this, e) - } - return r(e, null, [{ - key: "supportMSEH264Playback", - value: function() { - return window.MediaSource && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"') - } - }, { - key: "supportNetworkStreamIO", - value: function() { - var e = new a.default({}, (0, o.createDefaultConfig)()), - t = e.loaderType; - return e.destroy(), "fetch-stream-loader" == t || "xhr-moz-chunked-loader" == t - } - }, { - key: "getNetworkLoaderTypeName", - value: function() { - var e = new a.default({}, (0, o.createDefaultConfig)()), - t = e.loaderType; - return e.destroy(), t - } - }, { - key: "supportNativeMediaPlayback", - value: function(t) { - void 0 == e.videoElement && (e.videoElement = window.document.createElement("video")); - var n = e.videoElement.canPlayType(t); - return "probably" === n || "maybe" == n - } - }, { - key: "getFeatureList", - value: function() { - var t = { - mseFlvPlayback: !1, - mseLiveFlvPlayback: !1, - networkStreamIO: !1, - networkLoaderName: "", - nativeMP4H264Playback: !1, - nativeWebmVP8Playback: !1, - nativeWebmVP9Playback: !1 - }; - return t.mseFlvPlayback = e.supportMSEH264Playback(), t.networkStreamIO = e.supportNetworkStreamIO(), t.networkLoaderName = e.getNetworkLoaderTypeName(), t.mseLiveFlvPlayback = t.mseFlvPlayback && t.networkStreamIO, t.nativeMP4H264Playback = e.supportNativeMediaPlayback('video/mp4; codecs="avc1.42001E, mp4a.40.2"'), t.nativeWebmVP8Playback = e.supportNativeMediaPlayback('video/webm; codecs="vp8.0, vorbis"'), t.nativeWebmVP9Playback = e.supportNativeMediaPlayback('video/webm; codecs="vp9"'), t - } - }]), e - }(); - n.default = u - }, { - "../config.js": 5, - "../io/io-controller.js": 23 - }], - 7: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = function() { - function e() { - i(this, e), this.mimeType = null, this.duration = null, this.hasAudio = null, this.hasVideo = null, this.audioCodec = null, this.videoCodec = null, this.audioDataRate = null, this.videoDataRate = null, this.audioSampleRate = null, this.audioChannelCount = null, this.width = null, this.height = null, this.fps = null, this.profile = null, this.level = null, this.refFrames = null, this.chromaFormat = null, this.sarNum = null, this.sarDen = null, this.metadata = null, this.segments = null, this.segmentCount = null, this.hasKeyframesIndex = null, this.keyframesIndex = null - } - return r(e, [{ - key: "isComplete", - value: function() { - var e = !1 === this.hasAudio || !0 === this.hasAudio && null != this.audioCodec && null != this.audioSampleRate && null != this.audioChannelCount, - t = !1 === this.hasVideo || !0 === this.hasVideo && null != this.videoCodec && null != this.width && null != this.height && null != this.fps && null != this.profile && null != this.level && null != this.refFrames && null != this.chromaFormat && null != this.sarNum && null != this.sarDen; - return null != this.mimeType && null != this.duration && null != this.metadata && null != this.hasKeyframesIndex && e && t - } - }, { - key: "isSeekable", - value: function() { - return !0 === this.hasKeyframesIndex - } - }, { - key: "getNearestKeyframe", - value: function(e) { - if (null == this.keyframesIndex) return null; - var t = this.keyframesIndex, - n = this._search(t.times, e); - return { - index: n, - milliseconds: t.times[n], - fileposition: t.filepositions[n] - } - } - }, { - key: "_search", - value: function(e, t) { - var n = 0, - i = e.length - 1, - r = 0, - s = 0, - a = i; - for (t < e[0] && (n = 0, s = a + 1); s <= a;) { - if ((r = s + Math.floor((a - s) / 2)) === i || t >= e[r] && t < e[r + 1]) { - n = r; - break - } - e[r] < t ? s = r + 1 : a = r - 1 - } - return n - } - }]), e - }(); - n.default = s - }, {}], - 8: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(); - n.SampleInfo = function e(t, n, r, s, a) { - i(this, e), this.dts = t, this.pts = n, this.duration = r, this.originalDts = s, this.isSyncPoint = a, this.fileposition = null - }, n.MediaSegmentInfo = function() { - function e() { - i(this, e), this.beginDts = 0, this.endDts = 0, this.beginPts = 0, this.endPts = 0, this.originalBeginDts = 0, this.originalEndDts = 0, this.syncPoints = [], this.firstSample = null, this.lastSample = null - } - return r(e, [{ - key: "appendSyncPoint", - value: function(e) { - e.isSyncPoint = !0, this.syncPoints.push(e) - } - }]), e - }(), n.IDRSampleList = function() { - function e() { - i(this, e), this._list = [] - } - return r(e, [{ - key: "clear", - value: function() { - this._list = [] - } - }, { - key: "appendArray", - value: function(e) { - var t = this._list; - 0 !== e.length && (t.length > 0 && e[0].originalDts < t[t.length - 1].originalDts && this.clear(), Array.prototype.push.apply(t, e)) - } - }, { - key: "getLastSyncPointBeforeDts", - value: function(e) { - if (0 == this._list.length) return null; - var t = this._list, - n = 0, - i = t.length - 1, - r = 0, - s = 0, - a = i; - for (e < t[0].dts && (n = 0, s = a + 1); s <= a;) { - if ((r = s + Math.floor((a - s) / 2)) === i || e >= t[r].dts && e < t[r + 1].dts) { - n = r; - break - } - t[r].dts < e ? s = r + 1 : a = r - 1 - } - return this._list[n] - } - }]), e - }(), n.MediaSegmentInfoList = function() { - function e(t) { - i(this, e), this._type = t, this._list = [], this._lastAppendLocation = -1 - } - return r(e, [{ - key: "isEmpty", - value: function() { - return 0 === this._list.length - } - }, { - key: "clear", - value: function() { - this._list = [], this._lastAppendLocation = -1 - } - }, { - key: "_searchNearestSegmentBefore", - value: function(e) { - var t = this._list; - if (0 === t.length) return -2; - var n = t.length - 1, - i = 0, - r = 0, - s = n, - a = 0; - if (e < t[0].originalBeginDts) return a = -1; - for (; r <= s;) { - if ((i = r + Math.floor((s - r) / 2)) === n || e > t[i].lastSample.originalDts && e < t[i + 1].originalBeginDts) { - a = i; - break - } - t[i].originalBeginDts < e ? r = i + 1 : s = i - 1 - } - return a - } - }, { - key: "_searchNearestSegmentAfter", - value: function(e) { - return this._searchNearestSegmentBefore(e) + 1 - } - }, { - key: "append", - value: function(e) { - var t = this._list, - n = e, - i = this._lastAppendLocation, - r = 0; - 1 !== i && i < t.length && n.originalBeginDts >= t[i].lastSample.originalDts && (i === t.length - 1 || i < t.length - 1 && n.originalBeginDts < t[i + 1].originalBeginDts) ? r = i + 1 : t.length > 0 && (r = this._searchNearestSegmentBefore(n.originalBeginDts) + 1), this._lastAppendLocation = r, this._list.splice(r, 0, n) - } - }, { - key: "getLastSegmentBefore", - value: function(e) { - var t = this._searchNearestSegmentBefore(e); - return t >= 0 ? this._list[t] : null - } - }, { - key: "getLastSampleBefore", - value: function(e) { - var t = this.getLastSegmentBefore(e); - return null != t ? t.lastSample : null - } - }, { - key: "getLastSyncPointBefore", - value: function(e) { - for (var t = this._searchNearestSegmentBefore(e), n = this._list[t].syncPoints; 0 === n.length && t > 0;) t--, n = this._list[t].syncPoints; - return n.length > 0 ? n[n.length - 1] : null - } - }, { - key: "type", - get: function() { - return this._type - } - }, { - key: "length", - get: function() { - return this._list.length - } - }]), e - }() - }, {}], - 9: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var s = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - a = e("events"), - o = i(a), - u = e("../utils/logger.js"), - l = i(u), - d = e("../utils/browser.js"), - h = i(d), - f = e("./mse-events.js"), - c = i(f), - _ = e("./media-segment-info.js"), - m = e("../utils/exception.js"), - p = function() { - function e(t) { - r(this, e), this.TAG = "MSEController", this._config = t, this._emitter = new o.default, this._config.isLive && void 0 == this._config.autoCleanupSourceBuffer && (this._config.autoCleanupSourceBuffer = !0), this.e = { - onSourceOpen: this._onSourceOpen.bind(this), - onSourceEnded: this._onSourceEnded.bind(this), - onSourceClose: this._onSourceClose.bind(this), - onSourceBufferError: this._onSourceBufferError.bind(this), - onSourceBufferUpdateEnd: this._onSourceBufferUpdateEnd.bind(this) - }, this._mediaSource = null, this._mediaSourceObjectURL = null, this._mediaElement = null, this._isBufferFull = !1, this._hasPendingEos = !1, this._requireSetMediaDuration = !1, this._pendingMediaDuration = 0, this._pendingSourceBufferInit = [], this._mimeTypes = { - video: null, - audio: null - }, this._sourceBuffers = { - video: null, - audio: null - }, this._lastInitSegments = { - video: null, - audio: null - }, this._pendingSegments = { - video: [], - audio: [] - }, this._pendingRemoveRanges = { - video: [], - audio: [] - }, this._idrList = new _.IDRSampleList - } - return s(e, [{ - key: "destroy", - value: function() { - (this._mediaElement || this._mediaSource) && this.detachMediaElement(), this.e = null, this._emitter.removeAllListeners(), this._emitter = null - } - }, { - key: "on", - value: function(e, t) { - this._emitter.addListener(e, t) - } - }, { - key: "off", - value: function(e, t) { - this._emitter.removeListener(e, t) - } - }, { - key: "attachMediaElement", - value: function(e) { - if (this._mediaSource) throw new m.IllegalStateException("MediaSource has been attached to an HTMLMediaElement!"); - var t = this._mediaSource = new window.MediaSource; - t.addEventListener("sourceopen", this.e.onSourceOpen), t.addEventListener("sourceended", this.e.onSourceEnded), t.addEventListener("sourceclose", this.e.onSourceClose), this._mediaElement = e, this._mediaSourceObjectURL = window.URL.createObjectURL(this._mediaSource), e.src = this._mediaSourceObjectURL - } - }, { - key: "detachMediaElement", - value: function() { - if (this._mediaSource) { - var e = this._mediaSource; - for (var t in this._sourceBuffers) { - var n = this._pendingSegments[t]; - n.splice(0, n.length), this._pendingSegments[t] = null, this._pendingRemoveRanges[t] = null, this._lastInitSegments[t] = null; - var i = this._sourceBuffers[t]; - i && ("closed" !== e.readyState && (e.removeSourceBuffer(i), i.removeEventListener("error", this.e.onSourceBufferError), i.removeEventListener("updateend", this.e.onSourceBufferUpdateEnd)), this._mimeTypes[t] = null, this._sourceBuffers[t] = null) - } - if ("open" === e.readyState) try { - e.endOfStream() - } catch (e) { - l.default.e(this.TAG, e.message) - } - e.removeEventListener("sourceopen", this.e.onSourceOpen), e.removeEventListener("sourceended", this.e.onSourceEnded), e.removeEventListener("sourceclose", this.e.onSourceClose), this._pendingSourceBufferInit = [], this._isBufferFull = !1, this._idrList.clear(), this._mediaSource = null - } - this._mediaElement && (this._mediaElement.src = "", this._mediaElement.removeAttribute("src"), this._mediaElement = null), this._mediaSourceObjectURL && (window.URL.revokeObjectURL(this._mediaSourceObjectURL), this._mediaSourceObjectURL = null) - } - }, { - key: "appendInitSegment", - value: function(e, t) { - if (!this._mediaSource || "open" !== this._mediaSource.readyState) return this._pendingSourceBufferInit.push(e), void this._pendingSegments[e.type].push(e); - var n = e, - i = "" + n.container; - n.codec && n.codec.length > 0 && (i += ";codecs=" + n.codec); - var r = !1; - if (l.default.v(this.TAG, "Received Initialization Segment, mimeType: " + i), this._lastInitSegments[n.type] = n, i !== this._mimeTypes[n.type]) { - if (this._mimeTypes[n.type]) l.default.v(this.TAG, "Notice: " + n.type + " mimeType changed, origin: " + this._mimeTypes[n.type] + ", target: " + i); - else { - r = !0; - try { - var s = this._sourceBuffers[n.type] = this._mediaSource.addSourceBuffer(i); - s.addEventListener("error", this.e.onSourceBufferError), s.addEventListener("updateend", this.e.onSourceBufferUpdateEnd) - } catch (e) { - return l.default.e(this.TAG, e.message), void this._emitter.emit(c.default.ERROR, { - code: e.code, - msg: e.message - }) - } - } - this._mimeTypes[n.type] = i - } - t || this._pendingSegments[n.type].push(n), r || this._sourceBuffers[n.type] && !this._sourceBuffers[n.type].updating && this._doAppendSegments(), h.default.safari && "audio/mpeg" === n.container && n.mediaDuration > 0 && (this._requireSetMediaDuration = !0, this._pendingMediaDuration = n.mediaDuration / 1e3, this._updateMediaSourceDuration()) - } - }, { - key: "appendMediaSegment", - value: function(e) { - var t = e; - this._pendingSegments[t.type].push(t), this._config.autoCleanupSourceBuffer && this._needCleanupSourceBuffer() && this._doCleanupSourceBuffer(); - var n = this._sourceBuffers[t.type]; - !n || n.updating || this._hasPendingRemoveRanges() || this._doAppendSegments() - } - }, { - key: "seek", - value: function(e) { - for (var t in this._sourceBuffers) - if (this._sourceBuffers[t]) { - var n = this._sourceBuffers[t]; - if ("open" === this._mediaSource.readyState) try { - n.abort() - } catch (e) { - l.default.e(this.TAG, e.message) - } - this._idrList.clear(); - var i = this._pendingSegments[t]; - if (i.splice(0, i.length), "closed" !== this._mediaSource.readyState) { - for (var r = 0; r < n.buffered.length; r++) { - var s = n.buffered.start(r), - a = n.buffered.end(r); - this._pendingRemoveRanges[t].push({ - start: s, - end: a - }) - } - if (n.updating || this._doRemoveRanges(), h.default.safari) { - var o = this._lastInitSegments[t]; - o && (this._pendingSegments[t].push(o), n.updating || this._doAppendSegments()) - } - } - } - } - }, { - key: "endOfStream", - value: function() { - var e = this._mediaSource, - t = this._sourceBuffers; - if (!e || "open" !== e.readyState) return void(e && "closed" === e.readyState && this._hasPendingSegments() && (this._hasPendingEos = !0)); - t.video && t.video.updating || t.audio && t.audio.updating ? this._hasPendingEos = !0 : (this._hasPendingEos = !1, e.endOfStream()) - } - }, { - key: "getNearestKeyframe", - value: function(e) { - return this._idrList.getLastSyncPointBeforeDts(e) - } - }, { - key: "_needCleanupSourceBuffer", - value: function() { - if (!this._config.autoCleanupSourceBuffer) return !1; - var e = this._mediaElement.currentTime; - for (var t in this._sourceBuffers) { - var n = this._sourceBuffers[t]; - if (n) { - var i = n.buffered; - if (i.length >= 1 && e - i.start(0) >= this._config.autoCleanupMaxBackwardDuration) return !0 - } - } - return !1 - } - }, { - key: "_doCleanupSourceBuffer", - value: function() { - var e = this._mediaElement.currentTime; - for (var t in this._sourceBuffers) { - var n = this._sourceBuffers[t]; - if (n) { - for (var i = n.buffered, r = !1, s = 0; s < i.length; s++) { - var a = i.start(s), - o = i.end(s); - if (a <= e && e < o + 3) { - if (e - a >= this._config.autoCleanupMaxBackwardDuration) { - r = !0; - var u = e - this._config.autoCleanupMinBackwardDuration; - this._pendingRemoveRanges[t].push({ - start: a, - end: u - }) - } - } else o < e && (r = !0, this._pendingRemoveRanges[t].push({ - start: a, - end: o - })) - } - r && !n.updating && this._doRemoveRanges() - } - } - } - }, { - key: "_updateMediaSourceDuration", - value: function() { - var e = this._sourceBuffers; - if (0 !== this._mediaElement.readyState && "open" === this._mediaSource.readyState && !(e.video && e.video.updating || e.audio && e.audio.updating)) { - var t = this._mediaSource.duration, - n = this._pendingMediaDuration; - n > 0 && (isNaN(t) || n > t) && (l.default.v(this.TAG, "Update MediaSource duration from " + t + " to " + n), this._mediaSource.duration = n), this._requireSetMediaDuration = !1, this._pendingMediaDuration = 0 - } - } - }, { - key: "_doRemoveRanges", - value: function() { - for (var e in this._pendingRemoveRanges) - if (this._sourceBuffers[e] && !this._sourceBuffers[e].updating) - for (var t = this._sourceBuffers[e], n = this._pendingRemoveRanges[e]; n.length && !t.updating;) { - var i = n.shift(); - t.remove(i.start, i.end) - } - } - }, { - key: "_doAppendSegments", - value: function() { - var e = this._pendingSegments; - for (var t in e) - if (this._sourceBuffers[t] && !this._sourceBuffers[t].updating && e[t].length > 0) { - var n = e[t].shift(); - if (n.timestampOffset) { - var i = this._sourceBuffers[t].timestampOffset, - r = n.timestampOffset / 1e3, - s = Math.abs(i - r); - s > .1 && (l.default.v(this.TAG, "Update MPEG audio timestampOffset from " + i + " to " + r), this._sourceBuffers[t].timestampOffset = r), delete n.timestampOffset - } - if (!n.data || 0 === n.data.byteLength) continue; - try { - this._sourceBuffers[t].appendBuffer(n.data), this._isBufferFull = !1, "video" === t && n.hasOwnProperty("info") && this._idrList.appendArray(n.info.syncPoints) - } catch (e) { - this._pendingSegments[t].unshift(n), 22 === e.code ? (this._isBufferFull || this._emitter.emit(c.default.BUFFER_FULL), this._isBufferFull = !0) : (l.default.e(this.TAG, e.message), this._emitter.emit(c.default.ERROR, { - code: e.code, - msg: e.message - })) - } - } - } - }, { - key: "_onSourceOpen", - value: function() { - if (l.default.v(this.TAG, "MediaSource onSourceOpen"), this._mediaSource.removeEventListener("sourceopen", this.e.onSourceOpen), this._pendingSourceBufferInit.length > 0) - for (var e = this._pendingSourceBufferInit; e.length;) { - var t = e.shift(); - this.appendInitSegment(t, !0) - } - this._hasPendingSegments() && this._doAppendSegments(), this._emitter.emit(c.default.SOURCE_OPEN) - } - }, { - key: "_onSourceEnded", - value: function() { - l.default.v(this.TAG, "MediaSource onSourceEnded") - } - }, { - key: "_onSourceClose", - value: function() { - l.default.v(this.TAG, "MediaSource onSourceClose"), this._mediaSource && null != this.e && (this._mediaSource.removeEventListener("sourceopen", this.e.onSourceOpen), this._mediaSource.removeEventListener("sourceended", this.e.onSourceEnded), this._mediaSource.removeEventListener("sourceclose", this.e.onSourceClose)) - } - }, { - key: "_hasPendingSegments", - value: function() { - var e = this._pendingSegments; - return e.video.length > 0 || e.audio.length > 0 - } - }, { - key: "_hasPendingRemoveRanges", - value: function() { - var e = this._pendingRemoveRanges; - return e.video.length > 0 || e.audio.length > 0 - } - }, { - key: "_onSourceBufferUpdateEnd", - value: function() { - this._requireSetMediaDuration ? this._updateMediaSourceDuration() : this._hasPendingRemoveRanges() ? this._doRemoveRanges() : this._hasPendingSegments() ? this._doAppendSegments() : this._hasPendingEos && this.endOfStream(), this._emitter.emit(c.default.UPDATE_END) - } - }, { - key: "_onSourceBufferError", - value: function(e) { - l.default.e(this.TAG, "SourceBuffer Error: " + e) - } - }]), e - }(); - n.default = p - }, { - "../utils/browser.js": 39, - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "./media-segment-info.js": 8, - "./mse-events.js": 10, - events: 2 - }], - 10: [function(e, t, n) { - "use strict"; - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var i = { - ERROR: "error", - SOURCE_OPEN: "source_open", - UPDATE_END: "update_end", - BUFFER_FULL: "buffer_full" - }; - n.default = i - }, {}], - 11: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var s = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - a = e("events"), - o = i(a), - u = e("../utils/logger.js"), - l = i(u), - d = e("../utils/logging-control.js"), - h = i(d), - f = e("./transmuxing-controller.js"), - c = i(f), - _ = e("./transmuxing-events.js"), - m = i(_), - p = e("./transmuxing-worker.js"), - v = i(p), - g = e("./media-info.js"), - y = i(g), - E = function() { - function t(n, i) { - if (r(this, t), this.TAG = "Transmuxer", this._emitter = new o.default, i.enableWorker && "undefined" != typeof Worker) try { - var s = e("webworkify"); - this._worker = s(v.default), this._workerDestroying = !1, this._worker.addEventListener("message", this._onWorkerMessage.bind(this)), this._worker.postMessage({ - cmd: "init", - param: [n, i] - }), this.e = { - onLoggingConfigChanged: this._onLoggingConfigChanged.bind(this) - }, h.default.registerListener(this.e.onLoggingConfigChanged), this._worker.postMessage({ - cmd: "logging_config", - param: h.default.getConfig() - }) - } catch (e) { - l.default.e(this.TAG, "Error while initialize transmuxing worker, fallback to inline transmuxing"), this._worker = null, this._controller = new c.default(n, i) - } else this._controller = new c.default(n, i); - if (this._controller) { - var a = this._controller; - a.on(m.default.IO_ERROR, this._onIOError.bind(this)), a.on(m.default.DEMUX_ERROR, this._onDemuxError.bind(this)), a.on(m.default.INIT_SEGMENT, this._onInitSegment.bind(this)), a.on(m.default.MEDIA_SEGMENT, this._onMediaSegment.bind(this)), a.on(m.default.LOADING_COMPLETE, this._onLoadingComplete.bind(this)), a.on(m.default.RECOVERED_EARLY_EOF, this._onRecoveredEarlyEof.bind(this)), a.on(m.default.MEDIA_INFO, this._onMediaInfo.bind(this)), a.on(m.default.STATISTICS_INFO, this._onStatisticsInfo.bind(this)), a.on(m.default.RECOMMEND_SEEKPOINT, this._onRecommendSeekpoint.bind(this)) - } - } - return s(t, [{ - key: "destroy", - value: function() { - this._worker ? this._workerDestroying || (this._workerDestroying = !0, this._worker.postMessage({ - cmd: "destroy" - }), h.default.removeListener(this.e.onLoggingConfigChanged), this.e = null) : (this._controller.destroy(), this._controller = null), this._emitter.removeAllListeners(), this._emitter = null - } - }, { - key: "on", - value: function(e, t) { - this._emitter.addListener(e, t) - } - }, { - key: "off", - value: function(e, t) { - this._emitter.removeListener(e, t) - } - }, { - key: "hasWorker", - value: function() { - return null != this._worker - } - }, { - key: "open", - value: function() { - this._worker ? this._worker.postMessage({ - cmd: "start" - }) : this._controller.start() - } - }, { - key: "close", - value: function() { - this._worker ? this._worker.postMessage({ - cmd: "stop" - }) : this._controller.stop() - } - }, { - key: "seek", - value: function(e) { - this._worker ? this._worker.postMessage({ - cmd: "seek", - param: e - }) : this._controller.seek(e) - } - }, { - key: "pause", - value: function() { - this._worker ? this._worker.postMessage({ - cmd: "pause" - }) : this._controller.pause() - } - }, { - key: "resume", - value: function() { - this._worker ? this._worker.postMessage({ - cmd: "resume" - }) : this._controller.resume() - } - }, { - key: "_onInitSegment", - value: function(e, t) { - var n = this; - Promise.resolve().then(function() { - n._emitter.emit(m.default.INIT_SEGMENT, e, t) - }) - } - }, { - key: "_onMediaSegment", - value: function(e, t) { - var n = this; - Promise.resolve().then(function() { - n._emitter.emit(m.default.MEDIA_SEGMENT, e, t) - }) - } - }, { - key: "_onLoadingComplete", - value: function() { - var e = this; - Promise.resolve().then(function() { - e._emitter.emit(m.default.LOADING_COMPLETE) - }) - } - }, { - key: "_onRecoveredEarlyEof", - value: function() { - var e = this; - Promise.resolve().then(function() { - e._emitter.emit(m.default.RECOVERED_EARLY_EOF) - }) - } - }, { - key: "_onMediaInfo", - value: function(e) { - var t = this; - Promise.resolve().then(function() { - t._emitter.emit(m.default.MEDIA_INFO, e) - }) - } - }, { - key: "_onStatisticsInfo", - value: function(e) { - var t = this; - Promise.resolve().then(function() { - t._emitter.emit(m.default.STATISTICS_INFO, e) - }) - } - }, { - key: "_onIOError", - value: function(e, t) { - var n = this; - Promise.resolve().then(function() { - n._emitter.emit(m.default.IO_ERROR, e, t) - }) - } - }, { - key: "_onDemuxError", - value: function(e, t) { - var n = this; - Promise.resolve().then(function() { - n._emitter.emit(m.default.DEMUX_ERROR, e, t) - }) - } - }, { - key: "_onRecommendSeekpoint", - value: function(e) { - var t = this; - Promise.resolve().then(function() { - t._emitter.emit(m.default.RECOMMEND_SEEKPOINT, e) - }) - } - }, { - key: "_onLoggingConfigChanged", - value: function(e) { - this._worker && this._worker.postMessage({ - cmd: "logging_config", - param: e - }) - } - }, { - key: "_onWorkerMessage", - value: function(e) { - var t = e.data, - n = t.data; - if ("destroyed" === t.msg || this._workerDestroying) return this._workerDestroying = !1, this._worker.terminate(), void(this._worker = null); - switch (t.msg) { - case m.default.INIT_SEGMENT: - case m.default.MEDIA_SEGMENT: - this._emitter.emit(t.msg, n.type, n.data); - break; - case m.default.LOADING_COMPLETE: - case m.default.RECOVERED_EARLY_EOF: - this._emitter.emit(t.msg); - break; - case m.default.MEDIA_INFO: - Object.setPrototypeOf(n, y.default.prototype), this._emitter.emit(t.msg, n); - break; - case m.default.STATISTICS_INFO: - this._emitter.emit(t.msg, n); - break; - case m.default.IO_ERROR: - case m.default.DEMUX_ERROR: - this._emitter.emit(t.msg, n.type, n.info); - break; - case m.default.RECOMMEND_SEEKPOINT: - this._emitter.emit(t.msg, n); - break; - case "logcat_callback": - l.default.emitter.emit("log", n.type, n.logcat) - } - } - }]), t - }(); - n.default = E - }, { - "../utils/logger.js": 41, - "../utils/logging-control.js": 42, - "./media-info.js": 7, - "./transmuxing-controller.js": 12, - "./transmuxing-events.js": 13, - "./transmuxing-worker.js": 14, - events: 2, - webworkify: 4 - }], - 12: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var s = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - a = e("events"), - o = i(a), - u = e("../utils/logger.js"), - l = i(u), - d = e("../utils/browser.js"), - h = i(d), - f = e("./media-info.js"), - c = i(f), - _ = e("../demux/flv-demuxer.js"), - m = i(_), - p = e("../remux/mp4-remuxer.js"), - v = i(p), - g = e("../demux/demux-errors.js"), - y = i(g), - E = e("../io/io-controller.js"), - b = i(E), - S = e("./transmuxing-events.js"), - k = i(S), - L = (e("../io/loader.js"), function() { - function e(t, n) { - r(this, e), this.TAG = "TransmuxingController", this._emitter = new o.default, this._config = n, t.segments || (t.segments = [{ - duration: t.duration, - filesize: t.filesize, - url: t.url - }]), "boolean" != typeof t.cors && (t.cors = !0), "boolean" != typeof t.withCredentials && (t.withCredentials = !1), this._mediaDataSource = t, this._currentSegmentIndex = 0; - var i = 0; - this._mediaDataSource.segments.forEach(function(e) { - e.timestampBase = i, i += e.duration, e.cors = t.cors, e.withCredentials = t.withCredentials, n.referrerPolicy && (e.referrerPolicy = n.referrerPolicy) - }), isNaN(i) || this._mediaDataSource.duration === i || (this._mediaDataSource.duration = i), this._mediaInfo = null, this._demuxer = null, this._remuxer = null, this._ioctl = null, this._pendingSeekTime = null, this._pendingResolveSeekPoint = null, this._statisticsReporter = null - } - return s(e, [{ - key: "destroy", - value: function() { - this._mediaInfo = null, this._mediaDataSource = null, this._statisticsReporter && this._disableStatisticsReporter(), this._ioctl && (this._ioctl.destroy(), this._ioctl = null), this._demuxer && (this._demuxer.destroy(), this._demuxer = null), this._remuxer && (this._remuxer.destroy(), this._remuxer = null), this._emitter.removeAllListeners(), this._emitter = null - } - }, { - key: "on", - value: function(e, t) { - this._emitter.addListener(e, t) - } - }, { - key: "off", - value: function(e, t) { - this._emitter.removeListener(e, t) - } - }, { - key: "start", - value: function() { - this._loadSegment(0), this._enableStatisticsReporter() - } - }, { - key: "_loadSegment", - value: function(e, t) { - this._currentSegmentIndex = e; - var n = this._mediaDataSource.segments[e], - i = this._ioctl = new b.default(n, this._config, e); - i.onError = this._onIOException.bind(this), i.onSeeked = this._onIOSeeked.bind(this), i.onComplete = this._onIOComplete.bind(this), i.onRedirect = this._onIORedirect.bind(this), i.onRecoveredEarlyEof = this._onIORecoveredEarlyEof.bind(this), t ? this._demuxer.bindDataSource(this._ioctl) : i.onDataArrival = this._onInitChunkArrival.bind(this), i.open(t) - } - }, { - key: "stop", - value: function() { - this._internalAbort(), this._disableStatisticsReporter() - } - }, { - key: "_internalAbort", - value: function() { - this._ioctl && (this._ioctl.destroy(), this._ioctl = null) - } - }, { - key: "pause", - value: function() { - this._ioctl && this._ioctl.isWorking() && (this._ioctl.pause(), this._disableStatisticsReporter()) - } - }, { - key: "resume", - value: function() { - this._ioctl && this._ioctl.isPaused() && (this._ioctl.resume(), this._enableStatisticsReporter()) - } - }, { - key: "seek", - value: function(e) { - if (null != this._mediaInfo && this._mediaInfo.isSeekable()) { - var t = this._searchSegmentIndexContains(e); - if (t === this._currentSegmentIndex) { - var n = this._mediaInfo.segments[t]; - if (void 0 == n) this._pendingSeekTime = e; - else { - var i = n.getNearestKeyframe(e); - this._remuxer.seek(i.milliseconds), this._ioctl.seek(i.fileposition), this._pendingResolveSeekPoint = i.milliseconds - } - } else { - var r = this._mediaInfo.segments[t]; - if (void 0 == r) this._pendingSeekTime = e, this._internalAbort(), this._remuxer.seek(), this._remuxer.insertDiscontinuity(), this._loadSegment(t); - else { - var s = r.getNearestKeyframe(e); - this._internalAbort(), this._remuxer.seek(e), this._remuxer.insertDiscontinuity(), this._demuxer.resetMediaInfo(), this._demuxer.timestampBase = this._mediaDataSource.segments[t].timestampBase, this._loadSegment(t, s.fileposition), this._pendingResolveSeekPoint = s.milliseconds, this._reportSegmentMediaInfo(t) - } - } - this._enableStatisticsReporter() - } - } - }, { - key: "_searchSegmentIndexContains", - value: function(e) { - for (var t = this._mediaDataSource.segments, n = t.length - 1, i = 0; i < t.length; i++) - if (e < t[i].timestampBase) { - n = i - 1; - break - } return n - } - }, { - key: "_onInitChunkArrival", - value: function(e, t) { - var n = this, - i = null, - r = 0; - if (t > 0) this._demuxer.bindDataSource(this._ioctl), this._demuxer.timestampBase = this._mediaDataSource.segments[this._currentSegmentIndex].timestampBase, r = this._demuxer.parseChunks(e, t); - else if ((i = m.default.probe(e)).match) { - this._demuxer = new m.default(i, this._config), this._remuxer || (this._remuxer = new v.default(this._config)); - var s = this._mediaDataSource; - void 0 == s.duration || isNaN(s.duration) || (this._demuxer.overridedDuration = s.duration), "boolean" == typeof s.hasAudio && (this._demuxer.overridedHasAudio = s.hasAudio), "boolean" == typeof s.hasVideo && (this._demuxer.overridedHasVideo = s.hasVideo), this._demuxer.timestampBase = s.segments[this._currentSegmentIndex].timestampBase, this._demuxer.onError = this._onDemuxException.bind(this), this._demuxer.onMediaInfo = this._onMediaInfo.bind(this), this._remuxer.bindDataSource(this._demuxer.bindDataSource(this._ioctl)), this._remuxer.onInitSegment = this._onRemuxerInitSegmentArrival.bind(this), this._remuxer.onMediaSegment = this._onRemuxerMediaSegmentArrival.bind(this), r = this._demuxer.parseChunks(e, t) - } else i = null, l.default.e(this.TAG, "Non-FLV, Unsupported media type!"), Promise.resolve().then(function() { - n._internalAbort() - }), this._emitter.emit(k.default.DEMUX_ERROR, y.default.FORMAT_UNSUPPORTED, "Non-FLV, Unsupported media type"), r = 0; - return r - } - }, { - key: "_onMediaInfo", - value: function(e) { - var t = this; - null == this._mediaInfo && (this._mediaInfo = Object.assign({}, e), this._mediaInfo.keyframesIndex = null, this._mediaInfo.segments = [], this._mediaInfo.segmentCount = this._mediaDataSource.segments.length, Object.setPrototypeOf(this._mediaInfo, c.default.prototype)); - var n = Object.assign({}, e); - Object.setPrototypeOf(n, c.default.prototype), this._mediaInfo.segments[this._currentSegmentIndex] = n, this._reportSegmentMediaInfo(this._currentSegmentIndex), null != this._pendingSeekTime && Promise.resolve().then(function() { - var e = t._pendingSeekTime; - t._pendingSeekTime = null, t.seek(e) - }) - } - }, { - key: "_onIOSeeked", - value: function() { - this._remuxer.insertDiscontinuity() - } - }, { - key: "_onIOComplete", - value: function(e) { - var t = e, - n = t + 1; - n < this._mediaDataSource.segments.length ? (this._internalAbort(), this._remuxer.flushStashedSamples(), this._loadSegment(n)) : (this._remuxer.flushStashedSamples(), this._emitter.emit(k.default.LOADING_COMPLETE), this._disableStatisticsReporter()) - } - }, { - key: "_onIORedirect", - value: function(e) { - var t = this._ioctl.extraData; - this._mediaDataSource.segments[t].redirectedURL = e - } - }, { - key: "_onIORecoveredEarlyEof", - value: function() { - this._emitter.emit(k.default.RECOVERED_EARLY_EOF) - } - }, { - key: "_onIOException", - value: function(e, t) { - l.default.e(this.TAG, "IOException: type = " + e + ", code = " + t.code + ", msg = " + t.msg), this._emitter.emit(k.default.IO_ERROR, e, t), this._disableStatisticsReporter() - } - }, { - key: "_onDemuxException", - value: function(e, t) { - l.default.e(this.TAG, "DemuxException: type = " + e + ", info = " + t), this._emitter.emit(k.default.DEMUX_ERROR, e, t) - } - }, { - key: "_onRemuxerInitSegmentArrival", - value: function(e, t) { - this._emitter.emit(k.default.INIT_SEGMENT, e, t) - } - }, { - key: "_onRemuxerMediaSegmentArrival", - value: function(e, t) { - if (null == this._pendingSeekTime && (this._emitter.emit(k.default.MEDIA_SEGMENT, e, t), null != this._pendingResolveSeekPoint && "video" === e)) { - var n = t.info.syncPoints, - i = this._pendingResolveSeekPoint; - this._pendingResolveSeekPoint = null, h.default.safari && n.length > 0 && n[0].originalDts === i && (i = n[0].pts), this._emitter.emit(k.default.RECOMMEND_SEEKPOINT, i) - } - } - }, { - key: "_enableStatisticsReporter", - value: function() { - null == this._statisticsReporter && (this._statisticsReporter = self.setInterval(this._reportStatisticsInfo.bind(this), this._config.statisticsInfoReportInterval)) - } - }, { - key: "_disableStatisticsReporter", - value: function() { - this._statisticsReporter && (self.clearInterval(this._statisticsReporter), this._statisticsReporter = null) - } - }, { - key: "_reportSegmentMediaInfo", - value: function(e) { - var t = this._mediaInfo.segments[e], - n = Object.assign({}, t); - n.duration = this._mediaInfo.duration, n.segmentCount = this._mediaInfo.segmentCount, delete n.segments, delete n.keyframesIndex, this._emitter.emit(k.default.MEDIA_INFO, n) - } - }, { - key: "_reportStatisticsInfo", - value: function() { - var e = {}; - e.url = this._ioctl.currentURL, e.hasRedirect = this._ioctl.hasRedirect, e.hasRedirect && (e.redirectedURL = this._ioctl.currentRedirectedURL), e.speed = this._ioctl.currentSpeed, e.loaderType = this._ioctl.loaderType, e.currentSegmentIndex = this._currentSegmentIndex, e.totalSegmentCount = this._mediaDataSource.segments.length, this._emitter.emit(k.default.STATISTICS_INFO, e) - } - }]), e - }()); - n.default = L - }, { - "../demux/demux-errors.js": 16, - "../demux/flv-demuxer.js": 18, - "../io/io-controller.js": 23, - "../io/loader.js": 24, - "../remux/mp4-remuxer.js": 38, - "../utils/browser.js": 39, - "../utils/logger.js": 41, - "./media-info.js": 7, - "./transmuxing-events.js": 13, - events: 2 - }], - 13: [function(e, t, n) { - "use strict"; - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var i = { - IO_ERROR: "io_error", - DEMUX_ERROR: "demux_error", - INIT_SEGMENT: "init_segment", - MEDIA_SEGMENT: "media_segment", - LOADING_COMPLETE: "loading_complete", - RECOVERED_EARLY_EOF: "recovered_early_eof", - MEDIA_INFO: "media_info", - STATISTICS_INFO: "statistics_info", - RECOMMEND_SEEKPOINT: "recommend_seekpoint" - }; - n.default = i - }, {}], - 14: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = e("../utils/logger.js"), - s = (i(r), e("../utils/logging-control.js")), - a = i(s), - o = e("../utils/polyfill.js"), - u = i(o), - l = e("./transmuxing-controller.js"), - d = i(l), - h = e("./transmuxing-events.js"), - f = i(h), - c = function(e) { - function t(t, n) { - var i = { - msg: f.default.INIT_SEGMENT, - data: { - type: t, - data: n - } - }; - e.postMessage(i, [n.data]) - } - - function n(t, n) { - var i = { - msg: f.default.MEDIA_SEGMENT, - data: { - type: t, - data: n - } - }; - e.postMessage(i, [n.data]) - } - - function i() { - var t = { - msg: f.default.LOADING_COMPLETE - }; - e.postMessage(t) - } - - function r() { - var t = { - msg: f.default.RECOVERED_EARLY_EOF - }; - e.postMessage(t) - } - - function s(t) { - var n = { - msg: f.default.MEDIA_INFO, - data: t - }; - e.postMessage(n) - } - - function o(t) { - var n = { - msg: f.default.STATISTICS_INFO, - data: t - }; - e.postMessage(n) - } - - function l(t, n) { - e.postMessage({ - msg: f.default.IO_ERROR, - data: { - type: t, - info: n - } - }) - } - - function h(t, n) { - e.postMessage({ - msg: f.default.DEMUX_ERROR, - data: { - type: t, - info: n - } - }) - } - - function c(t) { - e.postMessage({ - msg: f.default.RECOMMEND_SEEKPOINT, - data: t - }) - } - - function _(t, n) { - e.postMessage({ - msg: "logcat_callback", - data: { - type: t, - logcat: n - } - }) - } - var m = null, - p = _.bind(this); - u.default.install(), e.addEventListener("message", function(u) { - switch (u.data.cmd) { - case "init": - m = new d.default(u.data.param[0], u.data.param[1]), m.on(f.default.IO_ERROR, l.bind(this)), m.on(f.default.DEMUX_ERROR, h.bind(this)), m.on(f.default.INIT_SEGMENT, t.bind(this)), m.on(f.default.MEDIA_SEGMENT, n.bind(this)), m.on(f.default.LOADING_COMPLETE, i.bind(this)), m.on(f.default.RECOVERED_EARLY_EOF, r.bind(this)), m.on(f.default.MEDIA_INFO, s.bind(this)), m.on(f.default.STATISTICS_INFO, o.bind(this)), m.on(f.default.RECOMMEND_SEEKPOINT, c.bind(this)); - break; - case "destroy": - m && (m.destroy(), m = null), e.postMessage({ - msg: "destroyed" - }); - break; - case "start": - m.start(); - break; - case "stop": - m.stop(); - break; - case "seek": - m.seek(u.data.param); - break; - case "pause": - m.pause(); - break; - case "resume": - m.resume(); - break; - case "logging_config": - var _ = u.data.param; - a.default.applyConfig(_), !0 === _.enableCallback ? a.default.addLogListener(p) : a.default.removeLogListener(p) - } - }) - }; - n.default = c - }, { - "../utils/logger.js": 41, - "../utils/logging-control.js": 42, - "../utils/polyfill.js": 43, - "./transmuxing-controller.js": 12, - "./transmuxing-events.js": 13 - }], - 15: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var s = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - a = e("../utils/logger.js"), - o = i(a), - u = e("../utils/utf8-conv.js"), - l = i(u), - d = e("../utils/exception.js"), - h = function() { - var e = new ArrayBuffer(2); - return new DataView(e).setInt16(0, 256, !0), 256 === new Int16Array(e)[0] - }(), - f = function() { - function e() { - r(this, e) - } - return s(e, null, [{ - key: "parseScriptData", - value: function(t, n, i) { - var r = {}; - try { - var s = e.parseValue(t, n, i), - a = e.parseValue(t, n + s.size, i - s.size); - r[s.data] = a.data - } catch (e) { - o.default.e("AMF", e.toString()) - } - return r - } - }, { - key: "parseObject", - value: function(t, n, i) { - if (i < 3) throw new d.IllegalStateException("Data not enough when parse ScriptDataObject"); - var r = e.parseString(t, n, i), - s = e.parseValue(t, n + r.size, i - r.size), - a = s.objectEnd; - return { - data: { - name: r.data, - value: s.data - }, - size: r.size + s.size, - objectEnd: a - } - } - }, { - key: "parseVariable", - value: function(t, n, i) { - return e.parseObject(t, n, i) - } - }, { - key: "parseString", - value: function(e, t, n) { - if (n < 2) throw new d.IllegalStateException("Data not enough when parse String"); - var i = new DataView(e, t, n), - r = i.getUint16(0, !h), - s = void 0; - return s = r > 0 ? (0, l.default)(new Uint8Array(e, t + 2, r)) : "", { - data: s, - size: 2 + r - } - } - }, { - key: "parseLongString", - value: function(e, t, n) { - if (n < 4) throw new d.IllegalStateException("Data not enough when parse LongString"); - var i = new DataView(e, t, n), - r = i.getUint32(0, !h), - s = void 0; - return s = r > 0 ? (0, l.default)(new Uint8Array(e, t + 4, r)) : "", { - data: s, - size: 4 + r - } - } - }, { - key: "parseDate", - value: function(e, t, n) { - if (n < 10) throw new d.IllegalStateException("Data size invalid when parse Date"); - var i = new DataView(e, t, n), - r = i.getFloat64(0, !h); - return r += 60 * i.getInt16(8, !h) * 1e3, { - data: new Date(r), - size: 10 - } - } - }, { - key: "parseValue", - value: function(t, n, i) { - if (i < 1) throw new d.IllegalStateException("Data not enough when parse Value"); - var r = new DataView(t, n, i), - s = 1, - a = r.getUint8(0), - u = void 0, - l = !1; - try { - switch (a) { - case 0: - u = r.getFloat64(1, !h), s += 8; - break; - case 1: - u = !!r.getUint8(1), s += 1; - break; - case 2: - var f = e.parseString(t, n + 1, i - 1); - u = f.data, s += f.size; - break; - case 3: - u = {}; - var c = 0; - for (9 == (16777215 & r.getUint32(i - 4, !h)) && (c = 3); s < i - 4;) { - var _ = e.parseObject(t, n + s, i - s - c); - if (_.objectEnd) break; - u[_.data.name] = _.data.value, s += _.size - } - if (s <= i - 3) { - 9 === (16777215 & r.getUint32(s - 1, !h)) && (s += 3) - } - break; - case 8: - u = {}, s += 4; - var m = 0; - for (9 == (16777215 & r.getUint32(i - 4, !h)) && (m = 3); s < i - 8;) { - var p = e.parseVariable(t, n + s, i - s - m); - if (p.objectEnd) break; - u[p.data.name] = p.data.value, s += p.size - } - if (s <= i - 3) { - 9 === (16777215 & r.getUint32(s - 1, !h)) && (s += 3) - } - break; - case 9: - u = void 0, s = 1, l = !0; - break; - case 10: - u = []; - var v = r.getUint32(1, !h); - s += 4; - for (var g = 0; g < v; g++) { - var y = e.parseValue(t, n + s, i - s); - u.push(y.data), s += y.size - } - break; - case 11: - var E = e.parseDate(t, n + 1, i - 1); - u = E.data, s += E.size; - break; - case 12: - var b = e.parseString(t, n + 1, i - 1); - u = b.data, s += b.size; - break; - default: - s = i, o.default.w("AMF", "Unsupported AMF value type " + a) - } - } catch (e) { - o.default.e("AMF", e.toString()) - } - return { - data: u, - size: s, - objectEnd: l - } - } - }]), e - }(); - n.default = f - }, { - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "../utils/utf8-conv.js": 44 - }], - 16: [function(e, t, n) { - "use strict"; - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var i = { - OK: "OK", - FORMAT_ERROR: "FormatError", - FORMAT_UNSUPPORTED: "FormatUnsupported", - CODEC_UNSUPPORTED: "CodecUnsupported" - }; - n.default = i - }, {}], - 17: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = e("../utils/exception.js"), - a = function() { - function e(t) { - i(this, e), this.TAG = "ExpGolomb", this._buffer = t, this._buffer_index = 0, this._total_bytes = t.byteLength, this._total_bits = 8 * t.byteLength, this._current_word = 0, this._current_word_bits_left = 0 - } - return r(e, [{ - key: "destroy", - value: function() { - this._buffer = null - } - }, { - key: "_fillCurrentWord", - value: function() { - var e = this._total_bytes - this._buffer_index; - if (e <= 0) throw new s.IllegalStateException("ExpGolomb: _fillCurrentWord() but no bytes available"); - var t = Math.min(4, e), - n = new Uint8Array(4); - n.set(this._buffer.subarray(this._buffer_index, this._buffer_index + t)), this._current_word = new DataView(n.buffer).getUint32(0, !1), this._buffer_index += t, this._current_word_bits_left = 8 * t - } - }, { - key: "readBits", - value: function(e) { - if (e > 32) throw new s.InvalidArgumentException("ExpGolomb: readBits() bits exceeded max 32bits!"); - if (e <= this._current_word_bits_left) { - var t = this._current_word >>> 32 - e; - return this._current_word <<= e, this._current_word_bits_left -= e, t - } - var n = this._current_word_bits_left ? this._current_word : 0; - n >>>= 32 - this._current_word_bits_left; - var i = e - this._current_word_bits_left; - this._fillCurrentWord(); - var r = Math.min(i, this._current_word_bits_left), - a = this._current_word >>> 32 - r; - return this._current_word <<= r, this._current_word_bits_left -= r, n = n << r | a - } - }, { - key: "readBool", - value: function() { - return 1 === this.readBits(1) - } - }, { - key: "readByte", - value: function() { - return this.readBits(8) - } - }, { - key: "_skipLeadingZero", - value: function() { - var e = void 0; - for (e = 0; e < this._current_word_bits_left; e++) - if (0 != (this._current_word & 2147483648 >>> e)) return this._current_word <<= e, this._current_word_bits_left -= e, e; - return this._fillCurrentWord(), e + this._skipLeadingZero() - } - }, { - key: "readUEG", - value: function() { - var e = this._skipLeadingZero(); - return this.readBits(e + 1) - 1 - } - }, { - key: "readSEG", - value: function() { - var e = this.readUEG(); - return 1 & e ? e + 1 >>> 1 : -1 * (e >>> 1) - } - }]), e - }(); - n.default = a - }, { - "../utils/exception.js": 40 - }], - 18: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - - function s(e, t) { - return e[t] << 24 | e[t + 1] << 16 | e[t + 2] << 8 | e[t + 3] - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var a = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { - return typeof e - } : function(e) { - return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e - }, - o = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - u = e("../utils/logger.js"), - l = i(u), - d = e("./amf-parser.js"), - h = i(d), - f = e("./sps-parser.js"), - c = i(f), - _ = e("./demux-errors.js"), - m = i(_), - p = e("../core/media-info.js"), - v = i(p), - g = e("../utils/exception.js"), - y = function() { - function e(t, n) { - r(this, e), this.TAG = "FLVDemuxer", this._config = n, this._onError = null, this._onMediaInfo = null, this._onTrackMetadata = null, this._onDataAvailable = null, this._dataOffset = t.dataOffset, this._firstParse = !0, this._dispatch = !1, this._hasAudio = t.hasAudioTrack, this._hasVideo = t.hasVideoTrack, this._hasAudioFlagOverrided = !1, this._hasVideoFlagOverrided = !1, this._audioInitialMetadataDispatched = !1, this._videoInitialMetadataDispatched = !1, this._mediaInfo = new v.default, this._mediaInfo.hasAudio = this._hasAudio, this._mediaInfo.hasVideo = this._hasVideo, this._metadata = null, this._audioMetadata = null, this._videoMetadata = null, this._naluLengthSize = 4, this._timestampBase = 0, this._timescale = 1e3, this._duration = 0, this._durationOverrided = !1, this._referenceFrameRate = { - fixed: !0, - fps: 23.976, - fps_num: 23976, - fps_den: 1e3 - }, this._flvSoundRateTable = [5500, 11025, 22050, 44100, 48e3], this._mpegSamplingRates = [96e3, 88200, 64e3, 48e3, 44100, 32e3, 24e3, 22050, 16e3, 12e3, 11025, 8e3, 7350], this._mpegAudioV10SampleRateTable = [44100, 48e3, 32e3, 0], this._mpegAudioV20SampleRateTable = [22050, 24e3, 16e3, 0], this._mpegAudioV25SampleRateTable = [11025, 12e3, 8e3, 0], this._mpegAudioL1BitRateTable = [0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1], this._mpegAudioL2BitRateTable = [0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1], this._mpegAudioL3BitRateTable = [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1], this._videoTrack = { - type: "video", - id: 1, - sequenceNumber: 0, - samples: [], - length: 0 - }, this._audioTrack = { - type: "audio", - id: 2, - sequenceNumber: 0, - samples: [], - length: 0 - }, this._littleEndian = function() { - var e = new ArrayBuffer(2); - return new DataView(e).setInt16(0, 256, !0), 256 === new Int16Array(e)[0] - }() - } - return o(e, [{ - key: "destroy", - value: function() { - this._mediaInfo = null, this._metadata = null, this._audioMetadata = null, this._videoMetadata = null, this._videoTrack = null, this._audioTrack = null, this._onError = null, this._onMediaInfo = null, this._onTrackMetadata = null, this._onDataAvailable = null - } - }, { - key: "bindDataSource", - value: function(e) { - return e.onDataArrival = this.parseChunks.bind(this), this - } - }, { - key: "resetMediaInfo", - value: function() { - this._mediaInfo = new v.default - } - }, { - key: "_isInitialMetadataDispatched", - value: function() { - return this._hasAudio && this._hasVideo ? this._audioInitialMetadataDispatched && this._videoInitialMetadataDispatched : this._hasAudio && !this._hasVideo ? this._audioInitialMetadataDispatched : !(this._hasAudio || !this._hasVideo) && this._videoInitialMetadataDispatched - } - }, { - key: "parseChunks", - value: function(t, n) { - if (!(this._onError && this._onMediaInfo && this._onTrackMetadata && this._onDataAvailable)) throw new g.IllegalStateException("Flv: onError & onMediaInfo & onTrackMetadata & onDataAvailable callback must be specified"); - var i = 0, - r = this._littleEndian; - if (0 === n) { - if (!(t.byteLength > 13)) return 0; - i = e.probe(t).dataOffset - } - if (this._firstParse) { - this._firstParse = !1, n + i !== this._dataOffset && l.default.w(this.TAG, "First time parsing but chunk byteStart invalid!"); - 0 !== new DataView(t, i).getUint32(0, !r) && l.default.w(this.TAG, "PrevTagSize0 !== 0 !!!"), i += 4 - } - for (; i < t.byteLength;) { - this._dispatch = !0; - var s = new DataView(t, i); - if (i + 11 + 4 > t.byteLength) break; - var a = s.getUint8(0), - o = 16777215 & s.getUint32(0, !r); - if (i + 11 + o + 4 > t.byteLength) break; - if (8 === a || 9 === a || 18 === a) { - var u = s.getUint8(4), - d = s.getUint8(5), - h = s.getUint8(6), - f = s.getUint8(7), - c = h | d << 8 | u << 16 | f << 24; - 0 !== (16777215 & s.getUint32(7, !r)) && l.default.w(this.TAG, "Meet tag which has StreamID != 0!"); - var _ = i + 11; - switch (a) { - case 8: - this._parseAudioData(t, _, o, c); - break; - case 9: - this._parseVideoData(t, _, o, c, n + i); - break; - case 18: - this._parseScriptData(t, _, o) - } - var m = s.getUint32(11 + o, !r); - m !== 11 + o && l.default.w(this.TAG, "Invalid PrevTagSize " + m), i += 11 + o + 4 - } else l.default.w(this.TAG, "Unsupported tag type " + a + ", skipped"), i += 11 + o + 4 - } - return this._isInitialMetadataDispatched() && this._dispatch && (this._audioTrack.length || this._videoTrack.length) && this._onDataAvailable(this._audioTrack, this._videoTrack), i - } - }, { - key: "_parseScriptData", - value: function(e, t, n) { - var i = h.default.parseScriptData(e, t, n); - if (i.hasOwnProperty("onMetaData")) { - if (null == i.onMetaData || "object" !== a(i.onMetaData)) return void l.default.w(this.TAG, "Invalid onMetaData structure!"); - this._metadata && l.default.w(this.TAG, "Found another onMetaData tag!"), this._metadata = i; - var r = this._metadata.onMetaData; - if ("boolean" == typeof r.hasAudio && !1 === this._hasAudioFlagOverrided && (this._hasAudio = r.hasAudio, this._mediaInfo.hasAudio = this._hasAudio), "boolean" == typeof r.hasVideo && !1 === this._hasVideoFlagOverrided && (this._hasVideo = r.hasVideo, this._mediaInfo.hasVideo = this._hasVideo), "number" == typeof r.audiodatarate && (this._mediaInfo.audioDataRate = r.audiodatarate), "number" == typeof r.videodatarate && (this._mediaInfo.videoDataRate = r.videodatarate), "number" == typeof r.width && (this._mediaInfo.width = r.width), "number" == typeof r.height && (this._mediaInfo.height = r.height), "number" == typeof r.duration) { - if (!this._durationOverrided) { - var s = Math.floor(r.duration * this._timescale); - this._duration = s, this._mediaInfo.duration = s - } - } else this._mediaInfo.duration = 0; - if ("number" == typeof r.framerate) { - var o = Math.floor(1e3 * r.framerate); - if (o > 0) { - var u = o / 1e3; - this._referenceFrameRate.fixed = !0, this._referenceFrameRate.fps = u, this._referenceFrameRate.fps_num = o, this._referenceFrameRate.fps_den = 1e3, this._mediaInfo.fps = u - } - } - if ("object" === a(r.keyframes)) { - this._mediaInfo.hasKeyframesIndex = !0; - var d = r.keyframes; - this._mediaInfo.keyframesIndex = this._parseKeyframesIndex(d), r.keyframes = null - } else this._mediaInfo.hasKeyframesIndex = !1; - this._dispatch = !1, this._mediaInfo.metadata = r, l.default.v(this.TAG, "Parsed onMetaData"), this._mediaInfo.isComplete() && this._onMediaInfo(this._mediaInfo) - } - } - }, { - key: "_parseKeyframesIndex", - value: function(e) { - for (var t = [], n = [], i = 1; i < e.times.length; i++) { - var r = this._timestampBase + Math.floor(1e3 * e.times[i]); - t.push(r), n.push(e.filepositions[i]) - } - return { - times: t, - filepositions: n - } - } - }, { - key: "_parseAudioData", - value: function(e, t, n, i) { - if (n <= 1) return void l.default.w(this.TAG, "Flv: Invalid audio packet, missing SoundData payload!"); - if (!0 !== this._hasAudioFlagOverrided || !1 !== this._hasAudio) { - var r = (this._littleEndian, new DataView(e, t, n)), - s = r.getUint8(0), - a = s >>> 4; - if (2 !== a && 10 !== a) return void this._onError(m.default.CODEC_UNSUPPORTED, "Flv: Unsupported audio codec idx: " + a); - var o = 0, - u = (12 & s) >>> 2; - if (!(u >= 0 && u <= 4)) return void this._onError(m.default.FORMAT_ERROR, "Flv: Invalid audio sample rate idx: " + u); - o = this._flvSoundRateTable[u]; - var d = 1 & s, - h = this._audioMetadata, - f = this._audioTrack; - if (h || (!1 === this._hasAudio && !1 === this._hasAudioFlagOverrided && (this._hasAudio = !0, this._mediaInfo.hasAudio = !0), h = this._audioMetadata = {}, h.type = "audio", h.id = f.id, h.timescale = this._timescale, h.duration = this._duration, h.audioSampleRate = o, h.channelCount = 0 === d ? 1 : 2), 10 === a) { - var c = this._parseAACAudioData(e, t + 1, n - 1); - if (void 0 == c) return; - if (0 === c.packetType) { - h.config && l.default.w(this.TAG, "Found another AudioSpecificConfig!"); - var _ = c.data; - h.audioSampleRate = _.samplingRate, h.channelCount = _.channelCount, h.codec = _.codec, h.originalCodec = _.originalCodec, h.config = _.config, h.refSampleDuration = 1024 / h.audioSampleRate * h.timescale, l.default.v(this.TAG, "Parsed AudioSpecificConfig"), this._isInitialMetadataDispatched() ? this._dispatch && (this._audioTrack.length || this._videoTrack.length) && this._onDataAvailable(this._audioTrack, this._videoTrack) : this._audioInitialMetadataDispatched = !0, this._dispatch = !1, this._onTrackMetadata("audio", h); - var p = this._mediaInfo; - p.audioCodec = h.originalCodec, p.audioSampleRate = h.audioSampleRate, p.audioChannelCount = h.channelCount, p.hasVideo ? null != p.videoCodec && (p.mimeType = 'video/x-flv; codecs="' + p.videoCodec + "," + p.audioCodec + '"') : p.mimeType = 'video/x-flv; codecs="' + p.audioCodec + '"', p.isComplete() && this._onMediaInfo(p) - } else if (1 === c.packetType) { - var v = this._timestampBase + i, - g = { - unit: c.data, - length: c.data.byteLength, - dts: v, - pts: v - }; - f.samples.push(g), f.length += c.data.length - } else l.default.e(this.TAG, "Flv: Unsupported AAC data type " + c.packetType) - } else if (2 === a) { - if (!h.codec) { - var y = this._parseMP3AudioData(e, t + 1, n - 1, !0); - if (void 0 == y) return; - h.audioSampleRate = y.samplingRate, h.channelCount = y.channelCount, h.codec = y.codec, h.originalCodec = y.originalCodec, h.refSampleDuration = 1152 / h.audioSampleRate * h.timescale, l.default.v(this.TAG, "Parsed MPEG Audio Frame Header"), this._audioInitialMetadataDispatched = !0, this._onTrackMetadata("audio", h); - var E = this._mediaInfo; - E.audioCodec = h.codec, E.audioSampleRate = h.audioSampleRate, E.audioChannelCount = h.channelCount, E.audioDataRate = y.bitRate, E.hasVideo ? null != E.videoCodec && (E.mimeType = 'video/x-flv; codecs="' + E.videoCodec + "," + E.audioCodec + '"') : E.mimeType = 'video/x-flv; codecs="' + E.audioCodec + '"', E.isComplete() && this._onMediaInfo(E) - } - var b = this._parseMP3AudioData(e, t + 1, n - 1, !1); - if (void 0 == b) return; - var S = this._timestampBase + i, - k = { - unit: b, - length: b.byteLength, - dts: S, - pts: S - }; - f.samples.push(k), f.length += b.length - } - } - } - }, { - key: "_parseAACAudioData", - value: function(e, t, n) { - if (n <= 1) return void l.default.w(this.TAG, "Flv: Invalid AAC packet, missing AACPacketType or/and Data!"); - var i = {}, - r = new Uint8Array(e, t, n); - return i.packetType = r[0], 0 === r[0] ? i.data = this._parseAACAudioSpecificConfig(e, t + 1, n - 1) : i.data = r.subarray(1), i - } - }, { - key: "_parseAACAudioSpecificConfig", - value: function(e, t, n) { - var i = new Uint8Array(e, t, n), - r = null, - s = 0, - a = 0, - o = 0, - u = null; - if (s = a = i[0] >>> 3, (o = (7 & i[0]) << 1 | i[1] >>> 7) < 0 || o >= this._mpegSamplingRates.length) return void this._onError(m.default.FORMAT_ERROR, "Flv: AAC invalid sampling frequency index!"); - var l = this._mpegSamplingRates[o], - d = (120 & i[1]) >>> 3; - if (d < 0 || d >= 8) return void this._onError(m.default.FORMAT_ERROR, "Flv: AAC invalid channel configuration"); - 5 === s && (u = (7 & i[1]) << 1 | i[2] >>> 7, i[2]); - var h = self.navigator.userAgent.toLowerCase(); - return -1 !== h.indexOf("firefox") ? o >= 6 ? (s = 5, r = new Array(4), u = o - 3) : (s = 2, r = new Array(2), u = o) : -1 !== h.indexOf("android") ? (s = 2, r = new Array(2), u = o) : (s = 5, u = o, r = new Array(4), o >= 6 ? u = o - 3 : 1 === d && (s = 2, r = new Array(2), u = o)), r[0] = s << 3, r[0] |= (15 & o) >>> 1, r[1] = (15 & o) << 7, r[1] |= (15 & d) << 3, 5 === s && (r[1] |= (15 & u) >>> 1, r[2] = (1 & u) << 7, r[2] |= 8, r[3] = 0), { - config: r, - samplingRate: l, - channelCount: d, - codec: "mp4a.40." + s, - originalCodec: "mp4a.40." + a - } - } - }, { - key: "_parseMP3AudioData", - value: function(e, t, n, i) { - if (n < 4) return void l.default.w(this.TAG, "Flv: Invalid MP3 packet, header missing!"); - var r = (this._littleEndian, new Uint8Array(e, t, n)), - s = null; - if (i) { - if (255 !== r[0]) return; - var a = r[1] >>> 3 & 3, - o = (6 & r[1]) >> 1, - u = (240 & r[2]) >>> 4, - d = (12 & r[2]) >>> 2, - h = r[3] >>> 6 & 3, - f = 3 !== h ? 2 : 1, - c = 0, - _ = 0; - switch (a) { - case 0: - c = this._mpegAudioV25SampleRateTable[d]; - break; - case 2: - c = this._mpegAudioV20SampleRateTable[d]; - break; - case 3: - c = this._mpegAudioV10SampleRateTable[d] - } - switch (o) { - case 1: - 34, u < this._mpegAudioL3BitRateTable.length && (_ = this._mpegAudioL3BitRateTable[u]); - break; - case 2: - 33, u < this._mpegAudioL2BitRateTable.length && (_ = this._mpegAudioL2BitRateTable[u]); - break; - case 3: - 32, u < this._mpegAudioL1BitRateTable.length && (_ = this._mpegAudioL1BitRateTable[u]) - } - s = { - bitRate: _, - samplingRate: c, - channelCount: f, - codec: "mp3", - originalCodec: "mp3" - } - } else s = r; - return s - } - }, { - key: "_parseVideoData", - value: function(e, t, n, i, r) { - if (n <= 1) return void l.default.w(this.TAG, "Flv: Invalid video packet, missing VideoData payload!"); - if (!0 !== this._hasVideoFlagOverrided || !1 !== this._hasVideo) { - var s = new Uint8Array(e, t, n)[0], - a = (240 & s) >>> 4, - o = 15 & s; - if (7 !== o) return void this._onError(m.default.CODEC_UNSUPPORTED, "Flv: Unsupported codec in video frame: " + o); - this._parseAVCVideoPacket(e, t + 1, n - 1, i, r, a) - } - } - }, { - key: "_parseAVCVideoPacket", - value: function(e, t, n, i, r, s) { - if (n < 4) return void l.default.w(this.TAG, "Flv: Invalid AVC packet, missing AVCPacketType or/and CompositionTime"); - var a = this._littleEndian, - o = new DataView(e, t, n), - u = o.getUint8(0), - d = 16777215 & o.getUint32(0, !a), - h = d << 8 >> 8; - if (0 === u) this._parseAVCDecoderConfigurationRecord(e, t + 4, n - 4); - else if (1 === u) this._parseAVCVideoData(e, t + 4, n - 4, i, r, s, h); - else if (2 !== u) return void this._onError(m.default.FORMAT_ERROR, "Flv: Invalid video packet type " + u) - } - }, { - key: "_parseAVCDecoderConfigurationRecord", - value: function(e, t, n) { - if (n < 7) return void l.default.w(this.TAG, "Flv: Invalid AVCDecoderConfigurationRecord, lack of data!"); - var i = this._videoMetadata, - r = this._videoTrack, - s = this._littleEndian, - a = new DataView(e, t, n); - i ? void 0 !== i.avcc && l.default.w(this.TAG, "Found another AVCDecoderConfigurationRecord!") : (!1 === this._hasVideo && !1 === this._hasVideoFlagOverrided && (this._hasVideo = !0, this._mediaInfo.hasVideo = !0), i = this._videoMetadata = {}, i.type = "video", i.id = r.id, i.timescale = this._timescale, i.duration = this._duration); - var o = a.getUint8(0), - u = a.getUint8(1); - a.getUint8(2), a.getUint8(3); - if (1 !== o || 0 === u) return void this._onError(m.default.FORMAT_ERROR, "Flv: Invalid AVCDecoderConfigurationRecord"); - if (this._naluLengthSize = 1 + (3 & a.getUint8(4)), 3 !== this._naluLengthSize && 4 !== this._naluLengthSize) return void this._onError(m.default.FORMAT_ERROR, "Flv: Strange NaluLengthSizeMinusOne: " + (this._naluLengthSize - 1)); - var d = 31 & a.getUint8(5); - if (0 === d) return void this._onError(m.default.FORMAT_ERROR, "Flv: Invalid AVCDecoderConfigurationRecord: No SPS"); - d > 1 && l.default.w(this.TAG, "Flv: Strange AVCDecoderConfigurationRecord: SPS Count = " + d); - for (var h = 6, f = 0; f < d; f++) { - var _ = a.getUint16(h, !s); - if (h += 2, 0 !== _) { - var p = new Uint8Array(e, t + h, _); - h += _; - var v = c.default.parseSPS(p); - if (0 === f) { - i.codecWidth = v.codec_size.width, i.codecHeight = v.codec_size.height, i.presentWidth = v.present_size.width, i.presentHeight = v.present_size.height, i.profile = v.profile_string, i.level = v.level_string, i.bitDepth = v.bit_depth, i.chromaFormat = v.chroma_format, i.sarRatio = v.sar_ratio, i.frameRate = v.frame_rate, !1 !== v.frame_rate.fixed && 0 !== v.frame_rate.fps_num && 0 !== v.frame_rate.fps_den || (i.frameRate = this._referenceFrameRate); - var g = i.frameRate.fps_den, - y = i.frameRate.fps_num; - i.refSampleDuration = i.timescale * (g / y); - for (var E = p.subarray(1, 4), b = "avc1.", S = 0; S < 3; S++) { - var k = E[S].toString(16); - k.length < 2 && (k = "0" + k), b += k - } - i.codec = b; - var L = this._mediaInfo; - L.width = i.codecWidth, L.height = i.codecHeight, L.fps = i.frameRate.fps, L.profile = i.profile, L.level = i.level, L.refFrames = v.ref_frames, L.chromaFormat = v.chroma_format_string, L.sarNum = i.sarRatio.width, L.sarDen = i.sarRatio.height, L.videoCodec = b, L.hasAudio ? null != L.audioCodec && (L.mimeType = 'video/x-flv; codecs="' + L.videoCodec + "," + L.audioCodec + '"') : L.mimeType = 'video/x-flv; codecs="' + L.videoCodec + '"', L.isComplete() && this._onMediaInfo(L) - } - } - } - var w = a.getUint8(h); - if (0 === w) return void this._onError(m.default.FORMAT_ERROR, "Flv: Invalid AVCDecoderConfigurationRecord: No PPS"); - w > 1 && l.default.w(this.TAG, "Flv: Strange AVCDecoderConfigurationRecord: PPS Count = " + w), h++; - for (var R = 0; R < w; R++) { - var A = a.getUint16(h, !s); - h += 2, 0 !== A && (h += A) - } - i.avcc = new Uint8Array(n), i.avcc.set(new Uint8Array(e, t, n), 0), l.default.v(this.TAG, "Parsed AVCDecoderConfigurationRecord"), this._isInitialMetadataDispatched() ? this._dispatch && (this._audioTrack.length || this._videoTrack.length) && this._onDataAvailable(this._audioTrack, this._videoTrack) : this._videoInitialMetadataDispatched = !0, this._dispatch = !1, this._onTrackMetadata("video", i) - } - }, { - key: "_parseAVCVideoData", - value: function(e, t, n, i, r, s, a) { - for (var o = this._littleEndian, u = new DataView(e, t, n), d = [], h = 0, f = 0, c = this._naluLengthSize, _ = this._timestampBase + i, m = 1 === s; f < n;) { - if (f + 4 >= n) { - l.default.w(this.TAG, "Malformed Nalu near timestamp " + _ + ", offset = " + f + ", dataSize = " + n); - break - } - var p = u.getUint32(f, !o); - if (3 === c && (p >>>= 8), p > n - c) return void l.default.w(this.TAG, "Malformed Nalus near timestamp " + _ + ", NaluSize > DataSize!"); - var v = 31 & u.getUint8(f + c); - 5 === v && (m = !0); - var g = new Uint8Array(e, t + f, c + p), - y = { - type: v, - data: g - }; - d.push(y), h += g.byteLength, f += c + p - } - if (d.length) { - var E = this._videoTrack, - b = { - units: d, - length: h, - isKeyframe: m, - dts: _, - cts: a, - pts: _ + a - }; - m && (b.fileposition = r), E.samples.push(b), E.length += h - } - } - }, { - key: "onTrackMetadata", - get: function() { - return this._onTrackMetadata - }, - set: function(e) { - this._onTrackMetadata = e - } - }, { - key: "onMediaInfo", - get: function() { - return this._onMediaInfo - }, - set: function(e) { - this._onMediaInfo = e - } - }, { - key: "onError", - get: function() { - return this._onError - }, - set: function(e) { - this._onError = e - } - }, { - key: "onDataAvailable", - get: function() { - return this._onDataAvailable - }, - set: function(e) { - this._onDataAvailable = e - } - }, { - key: "timestampBase", - get: function() { - return this._timestampBase - }, - set: function(e) { - this._timestampBase = e - } - }, { - key: "overridedDuration", - get: function() { - return this._duration - }, - set: function(e) { - this._durationOverrided = !0, this._duration = e, this._mediaInfo.duration = e - } - }, { - key: "overridedHasAudio", - set: function(e) { - this._hasAudioFlagOverrided = !0, this._hasAudio = e, this._mediaInfo.hasAudio = e - } - }, { - key: "overridedHasVideo", - set: function(e) { - this._hasVideoFlagOverrided = !0, this._hasVideo = e, this._mediaInfo.hasVideo = e - } - }], [{ - key: "probe", - value: function(e) { - var t = new Uint8Array(e), - n = { - match: !1 - }; - if (70 !== t[0] || 76 !== t[1] || 86 !== t[2] || 1 !== t[3]) return n; - var i = (4 & t[4]) >>> 2 != 0, - r = 0 != (1 & t[4]), - a = s(t, 5); - return a < 9 ? n : { - match: !0, - consumed: a, - dataOffset: a, - hasAudioTrack: i, - hasVideoTrack: r - } - } - }]), e - }(); - n.default = y - }, { - "../core/media-info.js": 7, - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "./amf-parser.js": 15, - "./demux-errors.js": 16, - "./sps-parser.js": 19 - }], - 19: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = e("./exp-golomb.js"), - a = function(e) { - return e && e.__esModule ? e : { - default: e - } - }(s), - o = function() { - function e() { - i(this, e) - } - return r(e, null, [{ - key: "_ebsp2rbsp", - value: function(e) { - for (var t = e, n = t.byteLength, i = new Uint8Array(n), r = 0, s = 0; s < n; s++) s >= 2 && 3 === t[s] && 0 === t[s - 1] && 0 === t[s - 2] || (i[r] = t[s], r++); - return new Uint8Array(i.buffer, 0, r) - } - }, { - key: "parseSPS", - value: function(t) { - var n = e._ebsp2rbsp(t), - i = new a.default(n); - i.readByte(); - var r = i.readByte(); - i.readByte(); - var s = i.readByte(); - i.readUEG(); - var o = e.getProfileString(r), - u = e.getLevelString(s), - l = 1, - d = 420, - h = [0, 420, 422, 444], - f = 8; - if ((100 === r || 110 === r || 122 === r || 244 === r || 44 === r || 83 === r || 86 === r || 118 === r || 128 === r || 138 === r || 144 === r) && (l = i.readUEG(), 3 === l && i.readBits(1), l <= 3 && (d = h[l]), f = i.readUEG() + 8, i.readUEG(), i.readBits(1), i.readBool())) - for (var c = 3 !== l ? 8 : 12, _ = 0; _ < c; _++) i.readBool() && (_ < 6 ? e._skipScalingList(i, 16) : e._skipScalingList(i, 64)); - i.readUEG(); - var m = i.readUEG(); - if (0 === m) i.readUEG(); - else if (1 === m) { - i.readBits(1), i.readSEG(), i.readSEG(); - for (var p = i.readUEG(), v = 0; v < p; v++) i.readSEG() - } - var g = i.readUEG(); - i.readBits(1); - var y = i.readUEG(), - E = i.readUEG(), - b = i.readBits(1); - 0 === b && i.readBits(1), i.readBits(1); - var S = 0, - k = 0, - L = 0, - w = 0; - i.readBool() && (S = i.readUEG(), k = i.readUEG(), L = i.readUEG(), w = i.readUEG()); - var R = 1, - A = 1, - O = 0, - T = !0, - C = 0, - I = 0; - if (i.readBool()) { - if (i.readBool()) { - var x = i.readByte(), - M = [1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2], - D = [1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1]; - x > 0 && x < 16 ? (R = M[x - 1], A = D[x - 1]) : 255 === x && (R = i.readByte() << 8 | i.readByte(), A = i.readByte() << 8 | i.readByte()) - } - if (i.readBool() && i.readBool(), i.readBool() && (i.readBits(4), i.readBool() && i.readBits(24)), i.readBool() && (i.readUEG(), i.readUEG()), i.readBool()) { - var B = i.readBits(32), - j = i.readBits(32); - T = i.readBool(), C = j, I = 2 * B, O = C / I - } - } - var P = 1; - 1 === R && 1 === A || (P = R / A); - var U = 0, - N = 0; - if (0 === l) U = 1, N = 2 - b; - else { - var F = 3 === l ? 1 : 2, - G = 1 === l ? 2 : 1; - U = F, N = G * (2 - b) - } - var V = 16 * (y + 1), - z = 16 * (E + 1) * (2 - b); - V -= (S + k) * U, z -= (L + w) * N; - var H = Math.ceil(V * P); - return i.destroy(), i = null, { - profile_string: o, - level_string: u, - bit_depth: f, - ref_frames: g, - chroma_format: d, - chroma_format_string: e.getChromaFormatString(d), - frame_rate: { - fixed: T, - fps: O, - fps_den: I, - fps_num: C - }, - sar_ratio: { - width: R, - height: A - }, - codec_size: { - width: V, - height: z - }, - present_size: { - width: H, - height: z - } - } - } - }, { - key: "_skipScalingList", - value: function(e, t) { - for (var n = 8, i = 8, r = 0, s = 0; s < t; s++) 0 !== i && (r = e.readSEG(), i = (n + r + 256) % 256), n = 0 === i ? n : i - } - }, { - key: "getProfileString", - value: function(e) { - switch (e) { - case 66: - return "Baseline"; - case 77: - return "Main"; - case 88: - return "Extended"; - case 100: - return "High"; - case 110: - return "High10"; - case 122: - return "High422"; - case 244: - return "High444"; - default: - return "Unknown" - } - } - }, { - key: "getLevelString", - value: function(e) { - return (e / 10).toFixed(1) - } - }, { - key: "getChromaFormatString", - value: function(e) { - switch (e) { - case 420: - return "4:2:0"; - case 422: - return "4:2:2"; - case 444: - return "4:4:4"; - default: - return "Unknown" - } - } - }]), e - }(); - n.default = o - }, { - "./exp-golomb.js": 17 - }], - 20: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - var n = e; - if (null == n || "object" !== (void 0 === n ? "undefined" : o(n))) throw new b.InvalidArgumentException("MediaDataSource must be an javascript object!"); - if (!n.hasOwnProperty("type")) throw new b.InvalidArgumentException("MediaDataSource must has type field to indicate video file type!"); - switch (n.type) { - case "flv": - return new c.default(n, t); - default: - return new m.default(n, t) - } - } - - function s() { - return h.default.supportMSEH264Playback() - } - - function a() { - return h.default.getFeatureList() - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var o = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { - return typeof e - } : function(e) { - return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e - }, - u = e("./utils/polyfill.js"), - l = i(u), - d = e("./core/features.js"), - h = i(d), - f = e("./player/flv-player.js"), - c = i(f), - _ = e("./player/native-player.js"), - m = i(_), - p = e("./player/player-events.js"), - v = i(p), - g = e("./player/player-errors.js"), - y = e("./utils/logging-control.js"), - E = i(y), - b = e("./utils/exception.js"); - l.default.install(); - var S = {}; - S.createPlayer = r, S.isSupported = s, S.getFeatureList = a, S.Events = v.default, S.ErrorTypes = g.ErrorTypes, S.ErrorDetails = g.ErrorDetails, S.FlvPlayer = c.default, S.NativePlayer = m.default, S.LoggingControl = E.default, Object.defineProperty(S, "version", { - enumerable: !0, - get: function() { - return "1.4.2" - } - }), n.default = S - }, { - "./core/features.js": 6, - "./player/flv-player.js": 32, - "./player/native-player.js": 33, - "./player/player-errors.js": 34, - "./player/player-events.js": 35, - "./utils/exception.js": 40, - "./utils/logging-control.js": 42, - "./utils/polyfill.js": 43 - }], - 21: [function(e, t, n) { - "use strict"; - t.exports = e("./flv.js").default - }, { - "./flv.js": 20 - }], - 22: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - - function s(e, t) { - if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !t || "object" != typeof t && "function" != typeof t ? e : t - } - - function a(e, t) { - if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); - e.prototype = Object.create(t && t.prototype, { - constructor: { - value: e, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var o = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { - return typeof e - } : function(e) { - return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e - }, - u = function e(t, n, i) { - null === t && (t = Function.prototype); - var r = Object.getOwnPropertyDescriptor(t, n); - if (void 0 === r) { - var s = Object.getPrototypeOf(t); - return null === s ? void 0 : e(s, n, i) - } - if ("value" in r) return r.value; - var a = r.get; - if (void 0 !== a) return a.call(i) - }, - l = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - d = e("../utils/logger.js"), - h = (i(d), e("../utils/browser.js")), - f = i(h), - c = e("./loader.js"), - _ = e("../utils/exception.js"), - m = function(e) { - function t(e, n) { - r(this, t); - var i = s(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, "fetch-stream-loader")); - return i.TAG = "FetchStreamLoader", i._seekHandler = e, i._config = n, i._needStash = !0, i._requestAbort = !1, i._contentLength = null, i._receivedLength = 0, i - } - return a(t, e), l(t, null, [{ - key: "isSupported", - value: function() { - try { - var e = f.default.msedge && f.default.version.minor >= 15048, - t = !f.default.msedge || e; - return self.fetch && self.ReadableStream && t - } catch (e) { - return !1 - } - } - }]), l(t, [{ - key: "destroy", - value: function() { - this.isWorking() && this.abort(), u(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype), "destroy", this).call(this) - } - }, { - key: "open", - value: function(e, t) { - var n = this; - this._dataSource = e, this._range = t; - var i = e.url; - this._config.reuseRedirectedURL && void 0 != e.redirectedURL && (i = e.redirectedURL); - var r = this._seekHandler.getConfig(i, t), - s = new self.Headers; - if ("object" === o(r.headers)) { - var a = r.headers; - for (var u in a) a.hasOwnProperty(u) && s.append(u, a[u]) - } - var l = { - method: "GET", - headers: s, - mode: "cors", - cache: "default", - referrerPolicy: "no-referrer-when-downgrade" - }; - !1 === e.cors && (l.mode = "same-origin"), e.withCredentials && (l.credentials = "include"), e.referrerPolicy && (l.referrerPolicy = e.referrerPolicy), this._status = c.LoaderStatus.kConnecting, self.fetch(r.url, l).then(function(e) { - if (n._requestAbort) return n._requestAbort = !1, void(n._status = c.LoaderStatus.kIdle); - if (e.ok && e.status >= 200 && e.status <= 299) { - if (e.url !== r.url && n._onURLRedirect) { - var t = n._seekHandler.removeURLParameters(e.url); - n._onURLRedirect(t) - } - var i = e.headers.get("Content-Length"); - return null != i && (n._contentLength = parseInt(i), 0 !== n._contentLength && n._onContentLengthKnown && n._onContentLengthKnown(n._contentLength)), n._pump.call(n, e.body.getReader()) - } - if (n._status = c.LoaderStatus.kError, !n._onError) throw new _.RuntimeException("FetchStreamLoader: Http code invalid, " + e.status + " " + e.statusText); - n._onError(c.LoaderErrors.HTTP_STATUS_CODE_INVALID, { - code: e.status, - msg: e.statusText - }) - }).catch(function(e) { - if (n._status = c.LoaderStatus.kError, !n._onError) throw e; - n._onError(c.LoaderErrors.EXCEPTION, { - code: -1, - msg: e.message - }) - }) - } - }, { - key: "abort", - value: function() { - this._requestAbort = !0 - } - }, { - key: "_pump", - value: function(e) { - var t = this; - return e.read().then(function(n) { - if (n.done) - if (null !== t._contentLength && t._receivedLength < t._contentLength) { - t._status = c.LoaderStatus.kError; - var i = c.LoaderErrors.EARLY_EOF, - r = { - code: -1, - msg: "Fetch stream meet Early-EOF" - }; - if (!t._onError) throw new _.RuntimeException(r.msg); - t._onError(i, r) - } else t._status = c.LoaderStatus.kComplete, t._onComplete && t._onComplete(t._range.from, t._range.from + t._receivedLength - 1); - else { - if (!0 === t._requestAbort) return t._requestAbort = !1, t._status = c.LoaderStatus.kComplete, e.cancel(); - t._status = c.LoaderStatus.kBuffering; - var s = n.value.buffer, - a = t._range.from + t._receivedLength; - t._receivedLength += s.byteLength, t._onDataArrival && t._onDataArrival(s, a, t._receivedLength), t._pump(e) - } - }).catch(function(e) { - if (11 !== e.code || !f.default.msedge) { - t._status = c.LoaderStatus.kError; - var n = 0, - i = null; - if (19 !== e.code && "network error" !== e.message || !(null === t._contentLength || null !== t._contentLength && t._receivedLength < t._contentLength) ? (n = c.LoaderErrors.EXCEPTION, i = { - code: e.code, - msg: e.message - }) : (n = c.LoaderErrors.EARLY_EOF, i = { - code: e.code, - msg: "Fetch stream meet Early-EOF" - }), !t._onError) throw new _.RuntimeException(i.msg); - t._onError(n, i) - } - }) - } - }]), t - }(c.BaseLoader); - n.default = m - }, { - "../utils/browser.js": 39, - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "./loader.js": 24 - }], - 23: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var s = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - a = e("../utils/logger.js"), - o = i(a), - u = e("./speed-sampler.js"), - l = i(u), - d = e("./loader.js"), - h = e("./fetch-stream-loader.js"), - f = i(h), - c = e("./xhr-moz-chunked-loader.js"), - _ = i(c), - m = e("./xhr-msstream-loader.js"), - p = (i(m), e("./xhr-range-loader.js")), - v = i(p), - g = e("./websocket-loader.js"), - y = i(g), - E = e("./range-seek-handler.js"), - b = i(E), - S = e("./param-seek-handler.js"), - k = i(S), - L = e("../utils/exception.js"), - w = function() { - function e(t, n, i) { - r(this, e), this.TAG = "IOController", this._config = n, this._extraData = i, this._stashInitialSize = 393216, void 0 != n.stashInitialSize && n.stashInitialSize > 0 && (this._stashInitialSize = n.stashInitialSize), this._stashUsed = 0, this._stashSize = this._stashInitialSize, this._bufferSize = 3145728, this._stashBuffer = new ArrayBuffer(this._bufferSize), this._stashByteStart = 0, this._enableStash = !0, !1 === n.enableStashBuffer && (this._enableStash = !1), this._loader = null, this._loaderClass = null, this._seekHandler = null, this._dataSource = t, this._isWebSocketURL = /wss?:\/\/(.+?)/.test(t.url), this._refTotalLength = t.filesize ? t.filesize : null, this._totalLength = this._refTotalLength, this._fullRequestFlag = !1, this._currentRange = null, this._redirectedURL = null, this._speedNormalized = 0, this._speedSampler = new l.default, this._speedNormalizeList = [64, 128, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096], this._isEarlyEofReconnecting = !1, this._paused = !1, this._resumeFrom = 0, this._onDataArrival = null, this._onSeeked = null, this._onError = null, this._onComplete = null, this._onRedirect = null, this._onRecoveredEarlyEof = null, this._selectSeekHandler(), this._selectLoader(), this._createLoader() - } - return s(e, [{ - key: "destroy", - value: function() { - this._loader.isWorking() && this._loader.abort(), this._loader.destroy(), this._loader = null, this._loaderClass = null, this._dataSource = null, this._stashBuffer = null, this._stashUsed = this._stashSize = this._bufferSize = this._stashByteStart = 0, this._currentRange = null, this._speedSampler = null, this._isEarlyEofReconnecting = !1, this._onDataArrival = null, this._onSeeked = null, this._onError = null, this._onComplete = null, this._onRedirect = null, this._onRecoveredEarlyEof = null, this._extraData = null - } - }, { - key: "isWorking", - value: function() { - return this._loader && this._loader.isWorking() && !this._paused - } - }, { - key: "isPaused", - value: function() { - return this._paused - } - }, { - key: "_selectSeekHandler", - value: function() { - var e = this._config; - if ("range" === e.seekType) this._seekHandler = new b.default(this._config.rangeLoadZeroStart); - else if ("param" === e.seekType) { - var t = e.seekParamStart || "bstart", - n = e.seekParamEnd || "bend"; - this._seekHandler = new k.default(t, n) - } else { - if ("custom" !== e.seekType) throw new L.InvalidArgumentException("Invalid seekType in config: " + e.seekType); - if ("function" != typeof e.customSeekHandler) throw new L.InvalidArgumentException("Custom seekType specified in config but invalid customSeekHandler!"); - this._seekHandler = new e.customSeekHandler - } - } - }, { - key: "_selectLoader", - value: function() { - if (this._isWebSocketURL) this._loaderClass = y.default; - else if (f.default.isSupported()) this._loaderClass = f.default; - else if (_.default.isSupported()) this._loaderClass = _.default; - else { - if (!v.default.isSupported()) throw new L.RuntimeException("Your browser doesn't support xhr with arraybuffer responseType!"); - this._loaderClass = v.default - } - } - }, { - key: "_createLoader", - value: function() { - this._loader = new this._loaderClass(this._seekHandler, this._config), !1 === this._loader.needStashBuffer && (this._enableStash = !1), this._loader.onContentLengthKnown = this._onContentLengthKnown.bind(this), this._loader.onURLRedirect = this._onURLRedirect.bind(this), this._loader.onDataArrival = this._onLoaderChunkArrival.bind(this), this._loader.onComplete = this._onLoaderComplete.bind(this), this._loader.onError = this._onLoaderError.bind(this) - } - }, { - key: "open", - value: function(e) { - this._currentRange = { - from: 0, - to: -1 - }, e && (this._currentRange.from = e), this._speedSampler.reset(), e || (this._fullRequestFlag = !0), this._loader.open(this._dataSource, Object.assign({}, this._currentRange)) - } - }, { - key: "abort", - value: function() { - this._loader.abort(), this._paused && (this._paused = !1, this._resumeFrom = 0) - } - }, { - key: "pause", - value: function() { - this.isWorking() && (this._loader.abort(), 0 !== this._stashUsed ? (this._resumeFrom = this._stashByteStart, this._currentRange.to = this._stashByteStart - 1) : this._resumeFrom = this._currentRange.to + 1, this._stashUsed = 0, this._stashByteStart = 0, this._paused = !0) - } - }, { - key: "resume", - value: function() { - if (this._paused) { - this._paused = !1; - var e = this._resumeFrom; - this._resumeFrom = 0, this._internalSeek(e, !0) - } - } - }, { - key: "seek", - value: function(e) { - this._paused = !1, this._stashUsed = 0, this._stashByteStart = 0, this._internalSeek(e, !0) - } - }, { - key: "_internalSeek", - value: function(e, t) { - this._loader.isWorking() && this._loader.abort(), this._flushStashBuffer(t), this._loader.destroy(), this._loader = null; - var n = { - from: e, - to: -1 - }; - this._currentRange = { - from: n.from, - to: -1 - }, this._speedSampler.reset(), this._stashSize = this._stashInitialSize, this._createLoader(), this._loader.open(this._dataSource, n), this._onSeeked && this._onSeeked() - } - }, { - key: "updateUrl", - value: function(e) { - if (!e || "string" != typeof e || 0 === e.length) throw new L.InvalidArgumentException("Url must be a non-empty string!"); - this._dataSource.url = e - } - }, { - key: "_expandBuffer", - value: function(e) { - for (var t = this._stashSize; t + 1048576 < e;) t *= 2; - if ((t += 1048576) !== this._bufferSize) { - var n = new ArrayBuffer(t); - if (this._stashUsed > 0) { - var i = new Uint8Array(this._stashBuffer, 0, this._stashUsed); - new Uint8Array(n, 0, t).set(i, 0) - } - this._stashBuffer = n, this._bufferSize = t - } - } - }, { - key: "_normalizeSpeed", - value: function(e) { - var t = this._speedNormalizeList, - n = t.length - 1, - i = 0, - r = 0, - s = n; - if (e < t[0]) return t[0]; - for (; r <= s;) { - if ((i = r + Math.floor((s - r) / 2)) === n || e >= t[i] && e < t[i + 1]) return t[i]; - t[i] < e ? r = i + 1 : s = i - 1 - } - } - }, { - key: "_adjustStashSize", - value: function(e) { - var t = 0; - (t = this._config.isLive ? e : e < 512 ? e : e >= 512 && e <= 1024 ? Math.floor(1.5 * e) : 2 * e) > 8192 && (t = 8192); - var n = 1024 * t + 1048576; - this._bufferSize < n && this._expandBuffer(n), this._stashSize = 1024 * t - } - }, { - key: "_dispatchChunks", - value: function(e, t) { - return this._currentRange.to = t + e.byteLength - 1, this._onDataArrival(e, t) - } - }, { - key: "_onURLRedirect", - value: function(e) { - this._redirectedURL = e, this._onRedirect && this._onRedirect(e) - } - }, { - key: "_onContentLengthKnown", - value: function(e) { - e && this._fullRequestFlag && (this._totalLength = e, this._fullRequestFlag = !1) - } - }, { - key: "_onLoaderChunkArrival", - value: function(e, t, n) { - if (!this._onDataArrival) throw new L.IllegalStateException("IOController: No existing consumer (onDataArrival) callback!"); - if (!this._paused) { - this._isEarlyEofReconnecting && (this._isEarlyEofReconnecting = !1, this._onRecoveredEarlyEof && this._onRecoveredEarlyEof()), this._speedSampler.addBytes(e.byteLength); - var i = this._speedSampler.lastSecondKBps; - if (0 !== i) { - var r = this._normalizeSpeed(i); - this._speedNormalized !== r && (this._speedNormalized = r, this._adjustStashSize(r)) - } - if (this._enableStash) - if (0 === this._stashUsed && 0 === this._stashByteStart && (this._stashByteStart = t), this._stashUsed + e.byteLength <= this._stashSize) { - var s = new Uint8Array(this._stashBuffer, 0, this._stashSize); - s.set(new Uint8Array(e), this._stashUsed), this._stashUsed += e.byteLength - } else { - var a = new Uint8Array(this._stashBuffer, 0, this._bufferSize); - if (this._stashUsed > 0) { - var o = this._stashBuffer.slice(0, this._stashUsed), - u = this._dispatchChunks(o, this._stashByteStart); - if (u < o.byteLength) { - if (u > 0) { - var l = new Uint8Array(o, u); - a.set(l, 0), this._stashUsed = l.byteLength, this._stashByteStart += u - } - } else this._stashUsed = 0, this._stashByteStart += u; - this._stashUsed + e.byteLength > this._bufferSize && (this._expandBuffer(this._stashUsed + e.byteLength), a = new Uint8Array(this._stashBuffer, 0, this._bufferSize)), a.set(new Uint8Array(e), this._stashUsed), this._stashUsed += e.byteLength - } else { - var d = this._dispatchChunks(e, t); - if (d < e.byteLength) { - var h = e.byteLength - d; - h > this._bufferSize && (this._expandBuffer(h), a = new Uint8Array(this._stashBuffer, 0, this._bufferSize)), a.set(new Uint8Array(e, d), 0), this._stashUsed += h, this._stashByteStart = t + d - } - } - } - else if (0 === this._stashUsed) { - var f = this._dispatchChunks(e, t); - if (f < e.byteLength) { - var c = e.byteLength - f; - c > this._bufferSize && this._expandBuffer(c); - var _ = new Uint8Array(this._stashBuffer, 0, this._bufferSize); - _.set(new Uint8Array(e, f), 0), this._stashUsed += c, this._stashByteStart = t + f - } - } else { - this._stashUsed + e.byteLength > this._bufferSize && this._expandBuffer(this._stashUsed + e.byteLength); - var m = new Uint8Array(this._stashBuffer, 0, this._bufferSize); - m.set(new Uint8Array(e), this._stashUsed), this._stashUsed += e.byteLength; - var p = this._dispatchChunks(this._stashBuffer.slice(0, this._stashUsed), this._stashByteStart); - if (p < this._stashUsed && p > 0) { - var v = new Uint8Array(this._stashBuffer, p); - m.set(v, 0) - } - this._stashUsed -= p, this._stashByteStart += p - } - } - } - }, { - key: "_flushStashBuffer", - value: function(e) { - if (this._stashUsed > 0) { - var t = this._stashBuffer.slice(0, this._stashUsed), - n = this._dispatchChunks(t, this._stashByteStart), - i = t.byteLength - n; - if (n < t.byteLength) { - if (!e) { - if (n > 0) { - var r = new Uint8Array(this._stashBuffer, 0, this._bufferSize), - s = new Uint8Array(t, n); - r.set(s, 0), this._stashUsed = s.byteLength, this._stashByteStart += n - } - return 0 - } - o.default.w(this.TAG, i + " bytes unconsumed data remain when flush buffer, dropped") - } - return this._stashUsed = 0, this._stashByteStart = 0, i - } - return 0 - } - }, { - key: "_onLoaderComplete", - value: function(e, t) { - this._flushStashBuffer(!0), this._onComplete && this._onComplete(this._extraData) - } - }, { - key: "_onLoaderError", - value: function(e, t) { - switch (o.default.e(this.TAG, "Loader error, code = " + t.code + ", msg = " + t.msg), this._flushStashBuffer(!1), this._isEarlyEofReconnecting && (this._isEarlyEofReconnecting = !1, e = d.LoaderErrors.UNRECOVERABLE_EARLY_EOF), e) { - case d.LoaderErrors.EARLY_EOF: - if (!this._config.isLive && this._totalLength) { - var n = this._currentRange.to + 1; - return void(n < this._totalLength && (o.default.w(this.TAG, "Connection lost, trying reconnect..."), this._isEarlyEofReconnecting = !0, this._internalSeek(n, !1))) - } - e = d.LoaderErrors.UNRECOVERABLE_EARLY_EOF; - break; - case d.LoaderErrors.UNRECOVERABLE_EARLY_EOF: - case d.LoaderErrors.CONNECTING_TIMEOUT: - case d.LoaderErrors.HTTP_STATUS_CODE_INVALID: - case d.LoaderErrors.EXCEPTION: - } - if (!this._onError) throw new L.RuntimeException("IOException: " + t.msg); - this._onError(e, t) - } - }, { - key: "status", - get: function() { - return this._loader.status - } - }, { - key: "extraData", - get: function() { - return this._extraData - }, - set: function(e) { - this._extraData = e - } - }, { - key: "onDataArrival", - get: function() { - return this._onDataArrival - }, - set: function(e) { - this._onDataArrival = e - } - }, { - key: "onSeeked", - get: function() { - return this._onSeeked - }, - set: function(e) { - this._onSeeked = e - } - }, { - key: "onError", - get: function() { - return this._onError - }, - set: function(e) { - this._onError = e - } - }, { - key: "onComplete", - get: function() { - return this._onComplete - }, - set: function(e) { - this._onComplete = e - } - }, { - key: "onRedirect", - get: function() { - return this._onRedirect - }, - set: function(e) { - this._onRedirect = e - } - }, { - key: "onRecoveredEarlyEof", - get: function() { - return this._onRecoveredEarlyEof - }, - set: function(e) { - this._onRecoveredEarlyEof = e - } - }, { - key: "currentURL", - get: function() { - return this._dataSource.url - } - }, { - key: "hasRedirect", - get: function() { - return null != this._redirectedURL || void 0 != this._dataSource.redirectedURL - } - }, { - key: "currentRedirectedURL", - get: function() { - return this._redirectedURL || this._dataSource.redirectedURL - } - }, { - key: "currentSpeed", - get: function() { - return this._loaderClass === v.default ? this._loader.currentSpeed : this._speedSampler.lastSecondKBps - } - }, { - key: "loaderType", - get: function() { - return this._loader.type - } - }]), e - }(); - n.default = w - }, { - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "./fetch-stream-loader.js": 22, - "./loader.js": 24, - "./param-seek-handler.js": 25, - "./range-seek-handler.js": 26, - "./speed-sampler.js": 27, - "./websocket-loader.js": 28, - "./xhr-moz-chunked-loader.js": 29, - "./xhr-msstream-loader.js": 30, - "./xhr-range-loader.js": 31 - }], - 24: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }), n.BaseLoader = n.LoaderErrors = n.LoaderStatus = void 0; - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = e("../utils/exception.js"), - a = n.LoaderStatus = { - kIdle: 0, - kConnecting: 1, - kBuffering: 2, - kError: 3, - kComplete: 4 - }; - n.LoaderErrors = { - OK: "OK", - EXCEPTION: "Exception", - HTTP_STATUS_CODE_INVALID: "HttpStatusCodeInvalid", - CONNECTING_TIMEOUT: "ConnectingTimeout", - EARLY_EOF: "EarlyEof", - UNRECOVERABLE_EARLY_EOF: "UnrecoverableEarlyEof" - }, n.BaseLoader = function() { - function e(t) { - i(this, e), this._type = t || "undefined", this._status = a.kIdle, this._needStash = !1, this._onContentLengthKnown = null, this._onURLRedirect = null, this._onDataArrival = null, this._onError = null, this._onComplete = null - } - return r(e, [{ - key: "destroy", - value: function() { - this._status = a.kIdle, this._onContentLengthKnown = null, this._onURLRedirect = null, this._onDataArrival = null, this._onError = null, this._onComplete = null - } - }, { - key: "isWorking", - value: function() { - return this._status === a.kConnecting || this._status === a.kBuffering - } - }, { - key: "open", - value: function(e, t) { - throw new s.NotImplementedException("Unimplemented abstract function!") - } - }, { - key: "abort", - value: function() { - throw new s.NotImplementedException("Unimplemented abstract function!") - } - }, { - key: "type", - get: function() { - return this._type - } - }, { - key: "status", - get: function() { - return this._status - } - }, { - key: "needStashBuffer", - get: function() { - return this._needStash - } - }, { - key: "onContentLengthKnown", - get: function() { - return this._onContentLengthKnown - }, - set: function(e) { - this._onContentLengthKnown = e - } - }, { - key: "onURLRedirect", - get: function() { - return this._onURLRedirect - }, - set: function(e) { - this._onURLRedirect = e - } - }, { - key: "onDataArrival", - get: function() { - return this._onDataArrival - }, - set: function(e) { - this._onDataArrival = e - } - }, { - key: "onError", - get: function() { - return this._onError - }, - set: function(e) { - this._onError = e - } - }, { - key: "onComplete", - get: function() { - return this._onComplete - }, - set: function(e) { - this._onComplete = e - } - }]), e - }() - }, { - "../utils/exception.js": 40 - }], - 25: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = function() { - function e(t, n) { - i(this, e), this._startName = t, this._endName = n - } - return r(e, [{ - key: "getConfig", - value: function(e, t) { - var n = e; - if (0 !== t.from || -1 !== t.to) { - var i = !0; - 1 === n.indexOf("?") && (n += "?", i = !1), i && (n += "&"), n += this._startName + "=" + t.from.toString(), -1 !== t.to && (n += "&" + this._endName + "=" + t.to.toString()) - } - return { - url: n, - headers: {} - } - } - }, { - key: "removeURLParameters", - value: function(e) { - var t = e.split("?")[0], - n = void 0, - i = e.indexOf("?"); - 1 !== i && (n = e.substring(i + 1)); - var r = ""; - if (void 0 != n && n.length > 0) - for (var s = n.split("&"), a = 0; a < s.length; a++) { - var o = s[a].split("="), - u = a > 0; - o[0] !== this._startName && o[0] !== this._endName && (u && (r += "&"), r += s[a]) - } - return 0 === r.length ? t : t + "?" + r - } - }]), e - }(); - n.default = s - }, {}], - 26: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = function() { - function e(t) { - i(this, e), this._zeroStart = t || !1 - } - return r(e, [{ - key: "getConfig", - value: function(e, t) { - var n = {}; - if (0 !== t.from || -1 !== t.to) { - var i = void 0; - i = -1 !== t.to ? "bytes=" + t.from.toString() + "-" + t.to.toString() : "bytes=" + t.from.toString() + "-", n.Range = i - } else this._zeroStart && (n.Range = "bytes=0-"); - return { - url: e, - headers: n - } - } - }, { - key: "removeURLParameters", - value: function(e) { - return e - } - }]), e - }(); - n.default = s - }, {}], - 27: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = function() { - function e() { - i(this, e), this._firstCheckpoint = 0, this._lastCheckpoint = 0, this._intervalBytes = 0, this._totalBytes = 0, this._lastSecondBytes = 0, self.performance && self.performance.now ? this._now = self.performance.now.bind(self.performance) : this._now = Date.now - } - return r(e, [{ - key: "reset", - value: function() { - this._firstCheckpoint = this._lastCheckpoint = 0, this._totalBytes = this._intervalBytes = 0, this._lastSecondBytes = 0 - } - }, { - key: "addBytes", - value: function(e) { - 0 === this._firstCheckpoint ? (this._firstCheckpoint = this._now(), this._lastCheckpoint = this._firstCheckpoint, this._intervalBytes += e, this._totalBytes += e) : this._now() - this._lastCheckpoint < 1e3 ? (this._intervalBytes += e, this._totalBytes += e) : (this._lastSecondBytes = this._intervalBytes, this._intervalBytes = e, this._totalBytes += e, this._lastCheckpoint = this._now()) - } - }, { - key: "currentKBps", - get: function() { - this.addBytes(0); - var e = (this._now() - this._lastCheckpoint) / 1e3; - return 0 == e && (e = 1), this._intervalBytes / e / 1024 - } - }, { - key: "lastSecondKBps", - get: function() { - return this.addBytes(0), 0 !== this._lastSecondBytes ? this._lastSecondBytes / 1024 : this._now() - this._lastCheckpoint >= 500 ? this.currentKBps : 0 - } - }, { - key: "averageKBps", - get: function() { - var e = (this._now() - this._firstCheckpoint) / 1e3; - return this._totalBytes / e / 1024 - } - }]), e - }(); - n.default = s - }, {}], - 28: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - - function r(e, t) { - if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !t || "object" != typeof t && "function" != typeof t ? e : t - } - - function s(e, t) { - if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); - e.prototype = Object.create(t && t.prototype, { - constructor: { - value: e, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var a = function e(t, n, i) { - null === t && (t = Function.prototype); - var r = Object.getOwnPropertyDescriptor(t, n); - if (void 0 === r) { - var s = Object.getPrototypeOf(t); - return null === s ? void 0 : e(s, n, i) - } - if ("value" in r) return r.value; - var a = r.get; - if (void 0 !== a) return a.call(i) - }, - o = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - u = e("../utils/logger.js"), - l = (function(e) { - e && e.__esModule - }(u), e("./loader.js")), - d = e("../utils/exception.js"), - h = function(e) { - function t() { - i(this, t); - var e = r(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, "websocket-loader")); - return e.TAG = "WebSocketLoader", e._needStash = !0, e._ws = null, e._requestAbort = !1, e._receivedLength = 0, e - } - return s(t, e), o(t, null, [{ - key: "isSupported", - value: function() { - try { - return void 0 !== self.WebSocket - } catch (e) { - return !1 - } - } - }]), o(t, [{ - key: "destroy", - value: function() { - this._ws && this.abort(), a(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype), "destroy", this).call(this) - } - }, { - key: "open", - value: function(e) { - try { - var t = this._ws = new self.WebSocket(e.url); - t.binaryType = "arraybuffer", t.onopen = this._onWebSocketOpen.bind(this), t.onclose = this._onWebSocketClose.bind(this), t.onmessage = this._onWebSocketMessage.bind(this), t.onerror = this._onWebSocketError.bind(this), this._status = l.LoaderStatus.kConnecting - } catch (e) { - this._status = l.LoaderStatus.kError; - var n = { - code: e.code, - msg: e.message - }; - if (!this._onError) throw new d.RuntimeException(n.msg); - this._onError(l.LoaderErrors.EXCEPTION, n) - } - } - }, { - key: "abort", - value: function() { - var e = this._ws; - !e || 0 !== e.readyState && 1 !== e.readyState || (this._requestAbort = !0, e.close()), this._ws = null, this._status = l.LoaderStatus.kComplete - } - }, { - key: "_onWebSocketOpen", - value: function(e) { - this._status = l.LoaderStatus.kBuffering - } - }, { - key: "_onWebSocketClose", - value: function(e) { - if (!0 === this._requestAbort) return void(this._requestAbort = !1); - this._status = l.LoaderStatus.kComplete, this._onComplete && this._onComplete(0, this._receivedLength - 1) - } - }, { - key: "_onWebSocketMessage", - value: function(e) { - var t = this; - if (e.data instanceof ArrayBuffer) this._dispatchArrayBuffer(e.data); - else if (e.data instanceof Blob) { - var n = new FileReader; - n.onload = function() { - t._dispatchArrayBuffer(n.result) - }, n.readAsArrayBuffer(e.data) - } else { - this._status = l.LoaderStatus.kError; - var i = { - code: -1, - msg: "Unsupported WebSocket message type: " + e.data.constructor.name - }; - if (!this._onError) throw new d.RuntimeException(i.msg); - this._onError(l.LoaderErrors.EXCEPTION, i) - } - } - }, { - key: "_dispatchArrayBuffer", - value: function(e) { - var t = e, - n = this._receivedLength; - this._receivedLength += t.byteLength, this._onDataArrival && this._onDataArrival(t, n, this._receivedLength) - } - }, { - key: "_onWebSocketError", - value: function(e) { - this._status = l.LoaderStatus.kError; - var t = { - code: e.code, - msg: e.message - }; - if (!this._onError) throw new d.RuntimeException(t.msg); - this._onError(l.LoaderErrors.EXCEPTION, t) - } - }]), t - }(l.BaseLoader); - n.default = h - }, { - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "./loader.js": 24 - }], - 29: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - - function r(e, t) { - if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !t || "object" != typeof t && "function" != typeof t ? e : t - } - - function s(e, t) { - if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); - e.prototype = Object.create(t && t.prototype, { - constructor: { - value: e, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var a = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { - return typeof e - } : function(e) { - return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e - }, - o = function e(t, n, i) { - null === t && (t = Function.prototype); - var r = Object.getOwnPropertyDescriptor(t, n); - if (void 0 === r) { - var s = Object.getPrototypeOf(t); - return null === s ? void 0 : e(s, n, i) - } - if ("value" in r) return r.value; - var a = r.get; - if (void 0 !== a) return a.call(i) - }, - u = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - l = e("../utils/logger.js"), - d = function(e) { - return e && e.__esModule ? e : { - default: e - } - }(l), - h = e("./loader.js"), - f = e("../utils/exception.js"), - c = function(e) { - function t(e, n) { - i(this, t); - var s = r(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, "xhr-moz-chunked-loader")); - return s.TAG = "MozChunkedLoader", s._seekHandler = e, s._config = n, s._needStash = !0, s._xhr = null, s._requestAbort = !1, s._contentLength = null, s._receivedLength = 0, s - } - return s(t, e), u(t, null, [{ - key: "isSupported", - value: function() { - try { - var e = new XMLHttpRequest; - return e.open("GET", "https://example.com", !0), e.responseType = "moz-chunked-arraybuffer", "moz-chunked-arraybuffer" === e.responseType - } catch (e) { - return d.default.w("MozChunkedLoader", e.message), !1 - } - } - }]), u(t, [{ - key: "destroy", - value: function() { - this.isWorking() && this.abort(), this._xhr && (this._xhr.onreadystatechange = null, this._xhr.onprogress = null, this._xhr.onloadend = null, this._xhr.onerror = null, this._xhr = null), o(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype), "destroy", this).call(this) - } - }, { - key: "open", - value: function(e, t) { - this._dataSource = e, this._range = t; - var n = e.url; - this._config.reuseRedirectedURL && void 0 != e.redirectedURL && (n = e.redirectedURL); - var i = this._seekHandler.getConfig(n, t); - this._requestURL = i.url; - var r = this._xhr = new XMLHttpRequest; - if (r.open("GET", i.url, !0), r.responseType = "moz-chunked-arraybuffer", r.onreadystatechange = this._onReadyStateChange.bind(this), r.onprogress = this._onProgress.bind(this), r.onloadend = this._onLoadEnd.bind(this), r.onerror = this._onXhrError.bind(this), e.withCredentials && (r.withCredentials = !0), "object" === a(i.headers)) { - var s = i.headers; - for (var o in s) s.hasOwnProperty(o) && r.setRequestHeader(o, s[o]) - } - this._status = h.LoaderStatus.kConnecting, r.send() - } - }, { - key: "abort", - value: function() { - this._requestAbort = !0, this._xhr && this._xhr.abort(), this._status = h.LoaderStatus.kComplete - } - }, { - key: "_onReadyStateChange", - value: function(e) { - var t = e.target; - if (2 === t.readyState) { - if (void 0 != t.responseURL && t.responseURL !== this._requestURL && this._onURLRedirect) { - var n = this._seekHandler.removeURLParameters(t.responseURL); - this._onURLRedirect(n) - } - if (0 !== t.status && (t.status < 200 || t.status > 299)) { - if (this._status = h.LoaderStatus.kError, !this._onError) throw new f.RuntimeException("MozChunkedLoader: Http code invalid, " + t.status + " " + t.statusText); - this._onError(h.LoaderErrors.HTTP_STATUS_CODE_INVALID, { - code: t.status, - msg: t.statusText - }) - } else this._status = h.LoaderStatus.kBuffering - } - } - }, { - key: "_onProgress", - value: function(e) { - if (this._status !== h.LoaderStatus.kError) { - null === this._contentLength && null !== e.total && 0 !== e.total && (this._contentLength = e.total, this._onContentLengthKnown && this._onContentLengthKnown(this._contentLength)); - var t = e.target.response, - n = this._range.from + this._receivedLength; - this._receivedLength += t.byteLength, this._onDataArrival && this._onDataArrival(t, n, this._receivedLength) - } - } - }, { - key: "_onLoadEnd", - value: function(e) { - if (!0 === this._requestAbort) return void(this._requestAbort = !1); - this._status !== h.LoaderStatus.kError && (this._status = h.LoaderStatus.kComplete, this._onComplete && this._onComplete(this._range.from, this._range.from + this._receivedLength - 1)) - } - }, { - key: "_onXhrError", - value: function(e) { - this._status = h.LoaderStatus.kError; - var t = 0, - n = null; - if (this._contentLength && e.loaded < this._contentLength ? (t = h.LoaderErrors.EARLY_EOF, n = { - code: -1, - msg: "Moz-Chunked stream meet Early-Eof" - }) : (t = h.LoaderErrors.EXCEPTION, n = { - code: -1, - msg: e.constructor.name + " " + e.type - }), !this._onError) throw new f.RuntimeException(n.msg); - this._onError(t, n) - } - }]), t - }(h.BaseLoader); - n.default = c - }, { - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "./loader.js": 24 - }], - 30: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - - function r(e, t) { - if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !t || "object" != typeof t && "function" != typeof t ? e : t - } - - function s(e, t) { - if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); - e.prototype = Object.create(t && t.prototype, { - constructor: { - value: e, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var a = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { - return typeof e - } : function(e) { - return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e - }, - o = function e(t, n, i) { - null === t && (t = Function.prototype); - var r = Object.getOwnPropertyDescriptor(t, n); - if (void 0 === r) { - var s = Object.getPrototypeOf(t); - return null === s ? void 0 : e(s, n, i) - } - if ("value" in r) return r.value; - var a = r.get; - if (void 0 !== a) return a.call(i) - }, - u = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - l = e("../utils/logger.js"), - d = function(e) { - return e && e.__esModule ? e : { - default: e - } - }(l), - h = e("./loader.js"), - f = e("../utils/exception.js"), - c = function(e) { - function t(e, n) { - i(this, t); - var s = r(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, "xhr-msstream-loader")); - return s.TAG = "MSStreamLoader", s._seekHandler = e, s._config = n, s._needStash = !0, s._xhr = null, s._reader = null, s._totalRange = null, s._currentRange = null, s._currentRequestURL = null, s._currentRedirectedURL = null, s._contentLength = null, s._receivedLength = 0, s._bufferLimit = 16777216, s._lastTimeBufferSize = 0, s._isReconnecting = !1, s - } - return s(t, e), u(t, null, [{ - key: "isSupported", - value: function() { - try { - if (void 0 === self.MSStream || void 0 === self.MSStreamReader) return !1; - var e = new XMLHttpRequest; - return e.open("GET", "https://example.com", !0), e.responseType = "ms-stream", "ms-stream" === e.responseType - } catch (e) { - return d.default.w("MSStreamLoader", e.message), !1 - } - } - }]), u(t, [{ - key: "destroy", - value: function() { - this.isWorking() && this.abort(), this._reader && (this._reader.onprogress = null, this._reader.onload = null, this._reader.onerror = null, this._reader = null), this._xhr && (this._xhr.onreadystatechange = null, this._xhr = null), o(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype), "destroy", this).call(this) - } - }, { - key: "open", - value: function(e, t) { - this._internalOpen(e, t, !1) - } - }, { - key: "_internalOpen", - value: function(e, t, n) { - this._dataSource = e, n ? this._currentRange = t : this._totalRange = t; - var i = e.url; - this._config.reuseRedirectedURL && (void 0 != this._currentRedirectedURL ? i = this._currentRedirectedURL : void 0 != e.redirectedURL && (i = e.redirectedURL)); - var r = this._seekHandler.getConfig(i, t); - this._currentRequestURL = r.url; - var s = this._reader = new self.MSStreamReader; - s.onprogress = this._msrOnProgress.bind(this), s.onload = this._msrOnLoad.bind(this), s.onerror = this._msrOnError.bind(this); - var o = this._xhr = new XMLHttpRequest; - if (o.open("GET", r.url, !0), o.responseType = "ms-stream", o.onreadystatechange = this._xhrOnReadyStateChange.bind(this), o.onerror = this._xhrOnError.bind(this), e.withCredentials && (o.withCredentials = !0), "object" === a(r.headers)) { - var u = r.headers; - for (var l in u) u.hasOwnProperty(l) && o.setRequestHeader(l, u[l]) - } - this._isReconnecting ? this._isReconnecting = !1 : this._status = h.LoaderStatus.kConnecting, o.send() - } - }, { - key: "abort", - value: function() { - this._internalAbort(), this._status = h.LoaderStatus.kComplete - } - }, { - key: "_internalAbort", - value: function() { - this._reader && (1 === this._reader.readyState && this._reader.abort(), this._reader.onprogress = null, this._reader.onload = null, this._reader.onerror = null, this._reader = null), this._xhr && (this._xhr.abort(), this._xhr.onreadystatechange = null, this._xhr = null) - } - }, { - key: "_xhrOnReadyStateChange", - value: function(e) { - var t = e.target; - if (2 === t.readyState) - if (t.status >= 200 && t.status <= 299) { - if (this._status = h.LoaderStatus.kBuffering, void 0 != t.responseURL) { - var n = this._seekHandler.removeURLParameters(t.responseURL); - t.responseURL !== this._currentRequestURL && n !== this._currentRedirectedURL && (this._currentRedirectedURL = n, this._onURLRedirect && this._onURLRedirect(n)) - } - var i = t.getResponseHeader("Content-Length"); - if (null != i && null == this._contentLength) { - var r = parseInt(i); - r > 0 && (this._contentLength = r, this._onContentLengthKnown && this._onContentLengthKnown(this._contentLength)) - } - } else { - if (this._status = h.LoaderStatus.kError, !this._onError) throw new f.RuntimeException("MSStreamLoader: Http code invalid, " + t.status + " " + t.statusText); - this._onError(h.LoaderErrors.HTTP_STATUS_CODE_INVALID, { - code: t.status, - msg: t.statusText - }) - } - else if (3 === t.readyState && t.status >= 200 && t.status <= 299) { - this._status = h.LoaderStatus.kBuffering; - var s = t.response; - this._reader.readAsArrayBuffer(s) - } - } - }, { - key: "_xhrOnError", - value: function(e) { - this._status = h.LoaderStatus.kError; - var t = h.LoaderErrors.EXCEPTION, - n = { - code: -1, - msg: e.constructor.name + " " + e.type - }; - if (!this._onError) throw new f.RuntimeException(n.msg); - this._onError(t, n) - } - }, { - key: "_msrOnProgress", - value: function(e) { - var t = e.target, - n = t.result; - if (null == n) return void this._doReconnectIfNeeded(); - var i = n.slice(this._lastTimeBufferSize); - this._lastTimeBufferSize = n.byteLength; - var r = this._totalRange.from + this._receivedLength; - this._receivedLength += i.byteLength, this._onDataArrival && this._onDataArrival(i, r, this._receivedLength), n.byteLength >= this._bufferLimit && (d.default.v(this.TAG, "MSStream buffer exceeded max size near " + (r + i.byteLength) + ", reconnecting..."), this._doReconnectIfNeeded()) - } - }, { - key: "_doReconnectIfNeeded", - value: function() { - if (null == this._contentLength || this._receivedLength < this._contentLength) { - this._isReconnecting = !0, this._lastTimeBufferSize = 0, this._internalAbort(); - var e = { - from: this._totalRange.from + this._receivedLength, - to: -1 - }; - this._internalOpen(this._dataSource, e, !0) - } - } - }, { - key: "_msrOnLoad", - value: function(e) { - this._status = h.LoaderStatus.kComplete, this._onComplete && this._onComplete(this._totalRange.from, this._totalRange.from + this._receivedLength - 1) - } - }, { - key: "_msrOnError", - value: function(e) { - this._status = h.LoaderStatus.kError; - var t = 0, - n = null; - if (this._contentLength && this._receivedLength < this._contentLength ? (t = h.LoaderErrors.EARLY_EOF, n = { - code: -1, - msg: "MSStream meet Early-Eof" - }) : (t = h.LoaderErrors.EARLY_EOF, n = { - code: -1, - msg: e.constructor.name + " " + e.type - }), !this._onError) throw new f.RuntimeException(n.msg); - this._onError(t, n) - } - }]), t - }(h.BaseLoader); - n.default = c - }, { - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "./loader.js": 24 - }], - 31: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - - function s(e, t) { - if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !t || "object" != typeof t && "function" != typeof t ? e : t - } - - function a(e, t) { - if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); - e.prototype = Object.create(t && t.prototype, { - constructor: { - value: e, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var o = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { - return typeof e - } : function(e) { - return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e - }, - u = function e(t, n, i) { - null === t && (t = Function.prototype); - var r = Object.getOwnPropertyDescriptor(t, n); - if (void 0 === r) { - var s = Object.getPrototypeOf(t); - return null === s ? void 0 : e(s, n, i) - } - if ("value" in r) return r.value; - var a = r.get; - if (void 0 !== a) return a.call(i) - }, - l = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - d = e("../utils/logger.js"), - h = i(d), - f = e("./speed-sampler.js"), - c = i(f), - _ = e("./loader.js"), - m = e("../utils/exception.js"), - p = function(e) { - function t(e, n) { - r(this, t); - var i = s(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, "xhr-range-loader")); - return i.TAG = "RangeLoader", i._seekHandler = e, i._config = n, i._needStash = !1, i._chunkSizeKBList = [128, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 5120, 6144, 7168, 8192], i._currentChunkSizeKB = 384, i._currentSpeedNormalized = 0, i._zeroSpeedChunkCount = 0, i._xhr = null, i._speedSampler = new c.default, i._requestAbort = !1, i._waitForTotalLength = !1, i._totalLengthReceived = !1, i._currentRequestURL = null, i._currentRedirectedURL = null, i._currentRequestRange = null, i._totalLength = null, i._contentLength = null, i._receivedLength = 0, i._lastTimeLoaded = 0, i - } - return a(t, e), l(t, null, [{ - key: "isSupported", - value: function() { - try { - var e = new XMLHttpRequest; - return e.open("GET", "https://example.com", !0), e.responseType = "arraybuffer", "arraybuffer" === e.responseType - } catch (e) { - return h.default.w("RangeLoader", e.message), !1 - } - } - }]), l(t, [{ - key: "destroy", - value: function() { - this.isWorking() && this.abort(), this._xhr && (this._xhr.onreadystatechange = null, this._xhr.onprogress = null, this._xhr.onload = null, this._xhr.onerror = null, this._xhr = null), u(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype), "destroy", this).call(this) - } - }, { - key: "open", - value: function(e, t) { - this._dataSource = e, this._range = t, this._status = _.LoaderStatus.kConnecting; - var n = !1; - void 0 != this._dataSource.filesize && 0 !== this._dataSource.filesize && (n = !0, this._totalLength = this._dataSource.filesize), this._totalLengthReceived || n ? this._openSubRange() : (this._waitForTotalLength = !0, this._internalOpen(this._dataSource, { - from: 0, - to: -1 - })) - } - }, { - key: "_openSubRange", - value: function() { - var e = 1024 * this._currentChunkSizeKB, - t = this._range.from + this._receivedLength, - n = t + e; - null != this._contentLength && n - this._range.from >= this._contentLength && (n = this._range.from + this._contentLength - 1), this._currentRequestRange = { - from: t, - to: n - }, this._internalOpen(this._dataSource, this._currentRequestRange) - } - }, { - key: "_internalOpen", - value: function(e, t) { - this._lastTimeLoaded = 0; - var n = e.url; - this._config.reuseRedirectedURL && (void 0 != this._currentRedirectedURL ? n = this._currentRedirectedURL : void 0 != e.redirectedURL && (n = e.redirectedURL)); - var i = this._seekHandler.getConfig(n, t); - this._currentRequestURL = i.url; - var r = this._xhr = new XMLHttpRequest; - if (r.open("GET", i.url, !0), r.responseType = "arraybuffer", r.onreadystatechange = this._onReadyStateChange.bind(this), r.onprogress = this._onProgress.bind(this), r.onload = this._onLoad.bind(this), r.onerror = this._onXhrError.bind(this), e.withCredentials && (r.withCredentials = !0), "object" === o(i.headers)) { - var s = i.headers; - for (var a in s) s.hasOwnProperty(a) && r.setRequestHeader(a, s[a]) - } - r.send() - } - }, { - key: "abort", - value: function() { - this._requestAbort = !0, this._internalAbort(), this._status = _.LoaderStatus.kComplete - } - }, { - key: "_internalAbort", - value: function() { - this._xhr && (this._xhr.onreadystatechange = null, this._xhr.onprogress = null, this._xhr.onload = null, this._xhr.onerror = null, this._xhr.abort(), this._xhr = null) - } - }, { - key: "_onReadyStateChange", - value: function(e) { - var t = e.target; - if (2 === t.readyState) { - if (void 0 != t.responseURL) { - var n = this._seekHandler.removeURLParameters(t.responseURL); - t.responseURL !== this._currentRequestURL && n !== this._currentRedirectedURL && (this._currentRedirectedURL = n, this._onURLRedirect && this._onURLRedirect(n)) - } - if (t.status >= 200 && t.status <= 299) { - if (this._waitForTotalLength) return; - this._status = _.LoaderStatus.kBuffering - } else { - if (this._status = _.LoaderStatus.kError, !this._onError) throw new m.RuntimeException("RangeLoader: Http code invalid, " + t.status + " " + t.statusText); - this._onError(_.LoaderErrors.HTTP_STATUS_CODE_INVALID, { - code: t.status, - msg: t.statusText - }) - } - } - } - }, { - key: "_onProgress", - value: function(e) { - if (this._status !== _.LoaderStatus.kError) { - if (null === this._contentLength) { - var t = !1; - if (this._waitForTotalLength) { - this._waitForTotalLength = !1, this._totalLengthReceived = !0, t = !0; - var n = e.total; - this._internalAbort(), null != n & 0 !== n && (this._totalLength = n) - } - if (-1 === this._range.to ? this._contentLength = this._totalLength - this._range.from : this._contentLength = this._range.to - this._range.from + 1, t) return void this._openSubRange(); - this._onContentLengthKnown && this._onContentLengthKnown(this._contentLength) - } - var i = e.loaded - this._lastTimeLoaded; - this._lastTimeLoaded = e.loaded, this._speedSampler.addBytes(i) - } - } - }, { - key: "_normalizeSpeed", - value: function(e) { - var t = this._chunkSizeKBList, - n = t.length - 1, - i = 0, - r = 0, - s = n; - if (e < t[0]) return t[0]; - for (; r <= s;) { - if ((i = r + Math.floor((s - r) / 2)) === n || e >= t[i] && e < t[i + 1]) return t[i]; - t[i] < e ? r = i + 1 : s = i - 1 - } - } - }, { - key: "_onLoad", - value: function(e) { - if (this._status !== _.LoaderStatus.kError) { - if (this._waitForTotalLength) return void(this._waitForTotalLength = !1); - this._lastTimeLoaded = 0; - var t = this._speedSampler.lastSecondKBps; - if (0 === t && ++this._zeroSpeedChunkCount >= 3 && (t = this._speedSampler.currentKBps), 0 !== t) { - var n = this._normalizeSpeed(t); - this._currentSpeedNormalized !== n && (this._currentSpeedNormalized = n, this._currentChunkSizeKB = n) - } - var i = e.target.response, - r = this._range.from + this._receivedLength; - this._receivedLength += i.byteLength; - var s = !1; - null != this._contentLength && this._receivedLength < this._contentLength ? this._openSubRange() : s = !0, this._onDataArrival && this._onDataArrival(i, r, this._receivedLength), s && (this._status = _.LoaderStatus.kComplete, this._onComplete && this._onComplete(this._range.from, this._range.from + this._receivedLength - 1)) - } - } - }, { - key: "_onXhrError", - value: function(e) { - this._status = _.LoaderStatus.kError; - var t = 0, - n = null; - if (this._contentLength && this._receivedLength > 0 && this._receivedLength < this._contentLength ? (t = _.LoaderErrors.EARLY_EOF, n = { - code: -1, - msg: "RangeLoader meet Early-Eof" - }) : (t = _.LoaderErrors.EXCEPTION, n = { - code: -1, - msg: e.constructor.name + " " + e.type - }), !this._onError) throw new m.RuntimeException(n.msg); - this._onError(t, n) - } - }, { - key: "currentSpeed", - get: function() { - return this._speedSampler.lastSecondKBps - } - }]), t - }(_.BaseLoader); - n.default = p - }, { - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "./loader.js": 24, - "./speed-sampler.js": 27 - }], - 32: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var s = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { - return typeof e - } : function(e) { - return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e - }, - a = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - o = e("events"), - u = i(o), - l = e("../utils/logger.js"), - d = i(l), - h = e("../utils/browser.js"), - f = i(h), - c = e("./player-events.js"), - _ = i(c), - m = e("../core/transmuxer.js"), - p = i(m), - v = e("../core/transmuxing-events.js"), - g = i(v), - y = e("../core/mse-controller.js"), - E = i(y), - b = e("../core/mse-events.js"), - S = i(b), - k = e("./player-errors.js"), - L = e("../config.js"), - w = e("../utils/exception.js"), - R = function() { - function e(t, n) { - if (r(this, e), this.TAG = "FlvPlayer", this._type = "FlvPlayer", this._emitter = new u.default, this._config = (0, L.createDefaultConfig)(), "object" === (void 0 === n ? "undefined" : s(n)) && Object.assign(this._config, n), "flv" !== t.type.toLowerCase()) throw new w.InvalidArgumentException("FlvPlayer requires an flv MediaDataSource input!"); - !0 === t.isLive && (this._config.isLive = !0), this.e = { - onvLoadedMetadata: this._onvLoadedMetadata.bind(this), - onvSeeking: this._onvSeeking.bind(this), - onvCanPlay: this._onvCanPlay.bind(this), - onvStalled: this._onvStalled.bind(this), - onvProgress: this._onvProgress.bind(this) - }, self.performance && self.performance.now ? this._now = self.performance.now.bind(self.performance) : this._now = Date.now, this._pendingSeekTime = null, this._requestSetTime = !1, this._seekpointRecord = null, this._progressChecker = null, this._mediaDataSource = t, this._mediaElement = null, this._msectl = null, this._transmuxer = null, this._mseSourceOpened = !1, this._hasPendingLoad = !1, this._receivedCanPlay = !1, this._mediaInfo = null, this._statisticsInfo = null; - var i = f.default.chrome && (f.default.version.major < 50 || 50 === f.default.version.major && f.default.version.build < 2661); - this._alwaysSeekKeyframe = !!(i || f.default.msedge || f.default.msie), this._alwaysSeekKeyframe && (this._config.accurateSeek = !1) - } - return a(e, [{ - key: "destroy", - value: function() { - null != this._progressChecker && (window.clearInterval(this._progressChecker), this._progressChecker = null), this._transmuxer && this.unload(), this._mediaElement && this.detachMediaElement(), this.e = null, this._mediaDataSource = null, this._emitter.removeAllListeners(), this._emitter = null - } - }, { - key: "on", - value: function(e, t) { - var n = this; - e === _.default.MEDIA_INFO ? null != this._mediaInfo && Promise.resolve().then(function() { - n._emitter.emit(_.default.MEDIA_INFO, n.mediaInfo) - }) : e === _.default.STATISTICS_INFO && null != this._statisticsInfo && Promise.resolve().then(function() { - n._emitter.emit(_.default.STATISTICS_INFO, n.statisticsInfo) - }), this._emitter.addListener(e, t) - } - }, { - key: "off", - value: function(e, t) { - this._emitter.removeListener(e, t) - } - }, { - key: "attachMediaElement", - value: function(e) { - var t = this; - if (this._mediaElement = e, e.addEventListener("loadedmetadata", this.e.onvLoadedMetadata), e.addEventListener("seeking", this.e.onvSeeking), e.addEventListener("canplay", this.e.onvCanPlay), e.addEventListener("stalled", this.e.onvStalled), e.addEventListener("progress", this.e.onvProgress), this._msectl = new E.default(this._config), this._msectl.on(S.default.UPDATE_END, this._onmseUpdateEnd.bind(this)), this._msectl.on(S.default.BUFFER_FULL, this._onmseBufferFull.bind(this)), this._msectl.on(S.default.SOURCE_OPEN, function() { - t._mseSourceOpened = !0, t._hasPendingLoad && (t._hasPendingLoad = !1, t.load()) - }), this._msectl.on(S.default.ERROR, function(e) { - t._emitter.emit(_.default.ERROR, k.ErrorTypes.MEDIA_ERROR, k.ErrorDetails.MEDIA_MSE_ERROR, e) - }), this._msectl.attachMediaElement(e), null != this._pendingSeekTime) try { - e.currentTime = this._pendingSeekTime, this._pendingSeekTime = null - } catch (e) {} - } - }, { - key: "detachMediaElement", - value: function() { - this._mediaElement && (this._msectl.detachMediaElement(), this._mediaElement.removeEventListener("loadedmetadata", this.e.onvLoadedMetadata), this._mediaElement.removeEventListener("seeking", this.e.onvSeeking), this._mediaElement.removeEventListener("canplay", this.e.onvCanPlay), this._mediaElement.removeEventListener("stalled", this.e.onvStalled), this._mediaElement.removeEventListener("progress", this.e.onvProgress), this._mediaElement = null), this._msectl && (this._msectl.destroy(), this._msectl = null) - } - }, { - key: "load", - value: function() { - var e = this; - if (!this._mediaElement) throw new w.IllegalStateException("HTMLMediaElement must be attached before load()!"); - if (this._transmuxer) throw new w.IllegalStateException("FlvPlayer.load() has been called, please call unload() first!"); - if (!this._hasPendingLoad) { - if (this._config.deferLoadAfterSourceOpen && !1 === this._mseSourceOpened) return void(this._hasPendingLoad = !0); - this._mediaElement.readyState > 0 && (this._requestSetTime = !0, this._mediaElement.currentTime = 0), this._transmuxer = new p.default(this._mediaDataSource, this._config), this._transmuxer.on(g.default.INIT_SEGMENT, function(t, n) { - e._msectl.appendInitSegment(n) - }), this._transmuxer.on(g.default.MEDIA_SEGMENT, function(t, n) { - if (e._msectl.appendMediaSegment(n), e._config.lazyLoad && !e._config.isLive) { - var i = e._mediaElement.currentTime; - n.info.endDts >= 1e3 * (i + e._config.lazyLoadMaxDuration) && null == e._progressChecker && (d.default.v(e.TAG, "Maximum buffering duration exceeded, suspend transmuxing task"), e._suspendTransmuxer()) - } - }), this._transmuxer.on(g.default.LOADING_COMPLETE, function() { - e._msectl.endOfStream(), e._emitter.emit(_.default.LOADING_COMPLETE) - }), - this._transmuxer.on(g.default.RECOVERED_EARLY_EOF, function() { - e._emitter.emit(_.default.RECOVERED_EARLY_EOF) - }), this._transmuxer.on(g.default.IO_ERROR, function(t, n) { - e._emitter.emit(_.default.ERROR, k.ErrorTypes.NETWORK_ERROR, t, n) - }), this._transmuxer.on(g.default.DEMUX_ERROR, function(t, n) { - e._emitter.emit(_.default.ERROR, k.ErrorTypes.MEDIA_ERROR, t, { - code: -1, - msg: n - }) - }), this._transmuxer.on(g.default.MEDIA_INFO, function(t) { - e._mediaInfo = t, e._emitter.emit(_.default.MEDIA_INFO, Object.assign({}, t)) - }), this._transmuxer.on(g.default.STATISTICS_INFO, function(t) { - e._statisticsInfo = e._fillStatisticsInfo(t), e._emitter.emit(_.default.STATISTICS_INFO, Object.assign({}, e._statisticsInfo)) - }), this._transmuxer.on(g.default.RECOMMEND_SEEKPOINT, function(t) { - e._mediaElement && !e._config.accurateSeek && (e._requestSetTime = !0, e._mediaElement.currentTime = t / 1e3) - }), this._transmuxer.open() - } - } - }, { - key: "unload", - value: function() { - this._mediaElement && this._mediaElement.pause(), this._msectl && this._msectl.seek(0), this._transmuxer && (this._transmuxer.close(), this._transmuxer.destroy(), this._transmuxer = null) - } - }, { - key: "play", - value: function() { - return this._mediaElement.play() - } - }, { - key: "pause", - value: function() { - this._mediaElement.pause() - } - }, { - key: "_fillStatisticsInfo", - value: function(e) { - if (e.playerType = this._type, !(this._mediaElement instanceof HTMLVideoElement)) return e; - var t = !0, - n = 0, - i = 0; - if (this._mediaElement.getVideoPlaybackQuality) { - var r = this._mediaElement.getVideoPlaybackQuality(); - n = r.totalVideoFrames, i = r.droppedVideoFrames - } else void 0 != this._mediaElement.webkitDecodedFrameCount ? (n = this._mediaElement.webkitDecodedFrameCount, i = this._mediaElement.webkitDroppedFrameCount) : t = !1; - return t && (e.decodedFrames = n, e.droppedFrames = i), e - } - }, { - key: "_onmseUpdateEnd", - value: function() { - if (this._config.lazyLoad && !this._config.isLive) { - for (var e = this._mediaElement.buffered, t = this._mediaElement.currentTime, n = 0, i = 0; i < e.length; i++) { - var r = e.start(i), - s = e.end(i); - if (r <= t && t < s) { - r, - n = s; - break - } - } - n >= t + this._config.lazyLoadMaxDuration && null == this._progressChecker && (d.default.v(this.TAG, "Maximum buffering duration exceeded, suspend transmuxing task"), this._suspendTransmuxer()) - } - } - }, { - key: "_onmseBufferFull", - value: function() { - d.default.v(this.TAG, "MSE SourceBuffer is full, suspend transmuxing task"), null == this._progressChecker && this._suspendTransmuxer() - } - }, { - key: "_suspendTransmuxer", - value: function() { - this._transmuxer && (this._transmuxer.pause(), null == this._progressChecker && (this._progressChecker = window.setInterval(this._checkProgressAndResume.bind(this), 1e3))) - } - }, { - key: "_checkProgressAndResume", - value: function() { - for (var e = this._mediaElement.currentTime, t = this._mediaElement.buffered, n = !1, i = 0; i < t.length; i++) { - var r = t.start(i), - s = t.end(i); - if (e >= r && e < s) { - e >= s - this._config.lazyLoadRecoverDuration && (n = !0); - break - } - } - n && (window.clearInterval(this._progressChecker), this._progressChecker = null, n && (d.default.v(this.TAG, "Continue loading from paused position"), this._transmuxer.resume())) - } - }, { - key: "_isTimepointBuffered", - value: function(e) { - for (var t = this._mediaElement.buffered, n = 0; n < t.length; n++) { - var i = t.start(n), - r = t.end(n); - if (e >= i && e < r) return !0 - } - return !1 - } - }, { - key: "_internalSeek", - value: function(e) { - var t = this._isTimepointBuffered(e), - n = !1, - i = 0; - if (e < 1 && this._mediaElement.buffered.length > 0) { - var r = this._mediaElement.buffered.start(0); - (r < 1 && e < r || f.default.safari) && (n = !0, i = f.default.safari ? .1 : r) - } - if (n) this._requestSetTime = !0, this._mediaElement.currentTime = i; - else if (t) { - if (this._alwaysSeekKeyframe) { - var s = this._msectl.getNearestKeyframe(Math.floor(1e3 * e)); - this._requestSetTime = !0, this._mediaElement.currentTime = null != s ? s.dts / 1e3 : e - } else this._requestSetTime = !0, this._mediaElement.currentTime = e; - null != this._progressChecker && this._checkProgressAndResume() - } else null != this._progressChecker && (window.clearInterval(this._progressChecker), this._progressChecker = null), this._msectl.seek(e), this._transmuxer.seek(Math.floor(1e3 * e)), this._config.accurateSeek && (this._requestSetTime = !0, this._mediaElement.currentTime = e) - } - }, { - key: "_checkAndApplyUnbufferedSeekpoint", - value: function() { - if (this._seekpointRecord) - if (this._seekpointRecord.recordTime <= this._now() - 100) { - var e = this._mediaElement.currentTime; - this._seekpointRecord = null, this._isTimepointBuffered(e) || (null != this._progressChecker && (window.clearTimeout(this._progressChecker), this._progressChecker = null), this._msectl.seek(e), this._transmuxer.seek(Math.floor(1e3 * e)), this._config.accurateSeek && (this._requestSetTime = !0, this._mediaElement.currentTime = e)) - } else window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50) - } - }, { - key: "_checkAndResumeStuckPlayback", - value: function(e) { - var t = this._mediaElement; - if (e || !this._receivedCanPlay || t.readyState < 2) { - var n = t.buffered; - n.length > 0 && t.currentTime < n.start(0) && (d.default.w(this.TAG, "Playback seems stuck at " + t.currentTime + ", seek to " + n.start(0)), this._requestSetTime = !0, this._mediaElement.currentTime = n.start(0), this._mediaElement.removeEventListener("progress", this.e.onvProgress)) - } else this._mediaElement.removeEventListener("progress", this.e.onvProgress) - } - }, { - key: "_onvLoadedMetadata", - value: function(e) { - null != this._pendingSeekTime && (this._mediaElement.currentTime = this._pendingSeekTime, this._pendingSeekTime = null) - } - }, { - key: "_onvSeeking", - value: function(e) { - var t = this._mediaElement.currentTime, - n = this._mediaElement.buffered; - if (this._requestSetTime) return void(this._requestSetTime = !1); - if (t < 1 && n.length > 0) { - var i = n.start(0); - if (i < 1 && t < i || f.default.safari) return this._requestSetTime = !0, void(this._mediaElement.currentTime = f.default.safari ? .1 : i) - } - if (this._isTimepointBuffered(t)) { - if (this._alwaysSeekKeyframe) { - var r = this._msectl.getNearestKeyframe(Math.floor(1e3 * t)); - null != r && (this._requestSetTime = !0, this._mediaElement.currentTime = r.dts / 1e3) - } - return void(null != this._progressChecker && this._checkProgressAndResume()) - } - this._seekpointRecord = { - seekPoint: t, - recordTime: this._now() - }, window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50) - } - }, { - key: "_onvCanPlay", - value: function(e) { - this._receivedCanPlay = !0, this._mediaElement.removeEventListener("canplay", this.e.onvCanPlay) - } - }, { - key: "_onvStalled", - value: function(e) { - this._checkAndResumeStuckPlayback(!0) - } - }, { - key: "_onvProgress", - value: function(e) { - this._checkAndResumeStuckPlayback() - } - }, { - key: "type", - get: function() { - return this._type - } - }, { - key: "buffered", - get: function() { - return this._mediaElement.buffered - } - }, { - key: "duration", - get: function() { - return this._mediaElement.duration - } - }, { - key: "volume", - get: function() { - return this._mediaElement.volume - }, - set: function(e) { - this._mediaElement.volume = e - } - }, { - key: "muted", - get: function() { - return this._mediaElement.muted - }, - set: function(e) { - this._mediaElement.muted = e - } - }, { - key: "currentTime", - get: function() { - return this._mediaElement ? this._mediaElement.currentTime : 0 - }, - set: function(e) { - this._mediaElement ? this._internalSeek(e) : this._pendingSeekTime = e - } - }, { - key: "mediaInfo", - get: function() { - return Object.assign({}, this._mediaInfo) - } - }, { - key: "statisticsInfo", - get: function() { - return null == this._statisticsInfo && (this._statisticsInfo = {}), this._statisticsInfo = this._fillStatisticsInfo(this._statisticsInfo), Object.assign({}, this._statisticsInfo) - } - }]), e - }(); - n.default = R - }, { - "../config.js": 5, - "../core/mse-controller.js": 9, - "../core/mse-events.js": 10, - "../core/transmuxer.js": 11, - "../core/transmuxing-events.js": 13, - "../utils/browser.js": 39, - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "./player-errors.js": 34, - "./player-events.js": 35, - events: 2 - }], - 33: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var s = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { - return typeof e - } : function(e) { - return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e - }, - a = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - o = e("events"), - u = i(o), - l = e("./player-events.js"), - d = i(l), - h = e("../config.js"), - f = e("../utils/exception.js"), - c = function() { - function e(t, n) { - if (r(this, e), this.TAG = "NativePlayer", this._type = "NativePlayer", this._emitter = new u.default, this._config = (0, h.createDefaultConfig)(), "object" === (void 0 === n ? "undefined" : s(n)) && Object.assign(this._config, n), "flv" === t.type.toLowerCase()) throw new f.InvalidArgumentException("NativePlayer does't support flv MediaDataSource input!"); - if (t.hasOwnProperty("segments")) throw new f.InvalidArgumentException("NativePlayer(" + t.type + ") doesn't support multipart playback!"); - this.e = { - onvLoadedMetadata: this._onvLoadedMetadata.bind(this) - }, this._pendingSeekTime = null, this._statisticsReporter = null, this._mediaDataSource = t, this._mediaElement = null - } - return a(e, [{ - key: "destroy", - value: function() { - this._mediaElement && (this.unload(), this.detachMediaElement()), this.e = null, this._mediaDataSource = null, this._emitter.removeAllListeners(), this._emitter = null - } - }, { - key: "on", - value: function(e, t) { - var n = this; - e === d.default.MEDIA_INFO ? null != this._mediaElement && 0 !== this._mediaElement.readyState && Promise.resolve().then(function() { - n._emitter.emit(d.default.MEDIA_INFO, n.mediaInfo) - }) : e === d.default.STATISTICS_INFO && null != this._mediaElement && 0 !== this._mediaElement.readyState && Promise.resolve().then(function() { - n._emitter.emit(d.default.STATISTICS_INFO, n.statisticsInfo) - }), this._emitter.addListener(e, t) - } - }, { - key: "off", - value: function(e, t) { - this._emitter.removeListener(e, t) - } - }, { - key: "attachMediaElement", - value: function(e) { - if (this._mediaElement = e, e.addEventListener("loadedmetadata", this.e.onvLoadedMetadata), null != this._pendingSeekTime) try { - e.currentTime = this._pendingSeekTime, this._pendingSeekTime = null - } catch (e) {} - } - }, { - key: "detachMediaElement", - value: function() { - this._mediaElement && (this._mediaElement.src = "", this._mediaElement.removeAttribute("src"), this._mediaElement.removeEventListener("loadedmetadata", this.e.onvLoadedMetadata), this._mediaElement = null), null != this._statisticsReporter && (window.clearInterval(this._statisticsReporter), this._statisticsReporter = null) - } - }, { - key: "load", - value: function() { - if (!this._mediaElement) throw new f.IllegalStateException("HTMLMediaElement must be attached before load()!"); - this._mediaElement.src = this._mediaDataSource.url, this._mediaElement.readyState > 0 && (this._mediaElement.currentTime = 0), this._mediaElement.preload = "auto", this._mediaElement.load(), this._statisticsReporter = window.setInterval(this._reportStatisticsInfo.bind(this), this._config.statisticsInfoReportInterval) - } - }, { - key: "unload", - value: function() { - this._mediaElement && (this._mediaElement.src = "", this._mediaElement.removeAttribute("src")), null != this._statisticsReporter && (window.clearInterval(this._statisticsReporter), this._statisticsReporter = null) - } - }, { - key: "play", - value: function() { - return this._mediaElement.play() - } - }, { - key: "pause", - value: function() { - this._mediaElement.pause() - } - }, { - key: "_onvLoadedMetadata", - value: function(e) { - null != this._pendingSeekTime && (this._mediaElement.currentTime = this._pendingSeekTime, this._pendingSeekTime = null), this._emitter.emit(d.default.MEDIA_INFO, this.mediaInfo) - } - }, { - key: "_reportStatisticsInfo", - value: function() { - this._emitter.emit(d.default.STATISTICS_INFO, this.statisticsInfo) - } - }, { - key: "type", - get: function() { - return this._type - } - }, { - key: "buffered", - get: function() { - return this._mediaElement.buffered - } - }, { - key: "duration", - get: function() { - return this._mediaElement.duration - } - }, { - key: "volume", - get: function() { - return this._mediaElement.volume - }, - set: function(e) { - this._mediaElement.volume = e - } - }, { - key: "muted", - get: function() { - return this._mediaElement.muted - }, - set: function(e) { - this._mediaElement.muted = e - } - }, { - key: "currentTime", - get: function() { - return this._mediaElement ? this._mediaElement.currentTime : 0 - }, - set: function(e) { - this._mediaElement ? this._mediaElement.currentTime = e : this._pendingSeekTime = e - } - }, { - key: "mediaInfo", - get: function() { - var e = this._mediaElement instanceof HTMLAudioElement ? "audio/" : "video/", - t = { - mimeType: e + this._mediaDataSource.type - }; - return this._mediaElement && (t.duration = Math.floor(1e3 * this._mediaElement.duration), this._mediaElement instanceof HTMLVideoElement && (t.width = this._mediaElement.videoWidth, t.height = this._mediaElement.videoHeight)), t - } - }, { - key: "statisticsInfo", - get: function() { - var e = { - playerType: this._type, - url: this._mediaDataSource.url - }; - if (!(this._mediaElement instanceof HTMLVideoElement)) return e; - var t = !0, - n = 0, - i = 0; - if (this._mediaElement.getVideoPlaybackQuality) { - var r = this._mediaElement.getVideoPlaybackQuality(); - n = r.totalVideoFrames, i = r.droppedVideoFrames - } else void 0 != this._mediaElement.webkitDecodedFrameCount ? (n = this._mediaElement.webkitDecodedFrameCount, i = this._mediaElement.webkitDroppedFrameCount) : t = !1; - return t && (e.decodedFrames = n, e.droppedFrames = i), e - } - }]), e - }(); - n.default = c - }, { - "../config.js": 5, - "../utils/exception.js": 40, - "./player-events.js": 35, - events: 2 - }], - 34: [function(e, t, n) { - "use strict"; - Object.defineProperty(n, "__esModule", { - value: !0 - }), n.ErrorDetails = n.ErrorTypes = void 0; - var i = e("../io/loader.js"), - r = e("../demux/demux-errors.js"), - s = function(e) { - return e && e.__esModule ? e : { - default: e - } - }(r); - n.ErrorTypes = { - NETWORK_ERROR: "NetworkError", - MEDIA_ERROR: "MediaError", - OTHER_ERROR: "OtherError" - }, n.ErrorDetails = { - NETWORK_EXCEPTION: i.LoaderErrors.EXCEPTION, - NETWORK_STATUS_CODE_INVALID: i.LoaderErrors.HTTP_STATUS_CODE_INVALID, - NETWORK_TIMEOUT: i.LoaderErrors.CONNECTING_TIMEOUT, - NETWORK_UNRECOVERABLE_EARLY_EOF: i.LoaderErrors.UNRECOVERABLE_EARLY_EOF, - MEDIA_MSE_ERROR: "MediaMSEError", - MEDIA_FORMAT_ERROR: s.default.FORMAT_ERROR, - MEDIA_FORMAT_UNSUPPORTED: s.default.FORMAT_UNSUPPORTED, - MEDIA_CODEC_UNSUPPORTED: s.default.CODEC_UNSUPPORTED - } - }, { - "../demux/demux-errors.js": 16, - "../io/loader.js": 24 - }], - 35: [function(e, t, n) { - "use strict"; - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var i = { - ERROR: "error", - LOADING_COMPLETE: "loading_complete", - RECOVERED_EARLY_EOF: "recovered_early_eof", - MEDIA_INFO: "media_info", - STATISTICS_INFO: "statistics_info" - }; - n.default = i - }, {}], - 36: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = function() { - function e() { - i(this, e) - } - return r(e, null, [{ - key: "getSilentFrame", - value: function(e, t) { - if ("mp4a.40.2" === e) { - if (1 === t) return new Uint8Array([0, 200, 0, 128, 35, 128]); - if (2 === t) return new Uint8Array([33, 0, 73, 144, 2, 25, 0, 35, 128]); - if (3 === t) return new Uint8Array([0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 142]); - if (4 === t) return new Uint8Array([0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 128, 44, 128, 8, 2, 56]); - if (5 === t) return new Uint8Array([0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 130, 48, 4, 153, 0, 33, 144, 2, 56]); - if (6 === t) return new Uint8Array([0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 130, 48, 4, 153, 0, 33, 144, 2, 0, 178, 0, 32, 8, 224]) - } else { - if (1 === t) return new Uint8Array([1, 64, 34, 128, 163, 78, 230, 128, 186, 8, 0, 0, 0, 28, 6, 241, 193, 10, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 94]); - if (2 === t) return new Uint8Array([1, 64, 34, 128, 163, 94, 230, 128, 186, 8, 0, 0, 0, 0, 149, 0, 6, 241, 161, 10, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 94]); - if (3 === t) return new Uint8Array([1, 64, 34, 128, 163, 94, 230, 128, 186, 8, 0, 0, 0, 0, 149, 0, 6, 241, 161, 10, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 94]) - } - return null - } - }]), e - }(); - n.default = s - }, {}], - 37: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = function() { - function e() { - i(this, e) - } - return r(e, null, [{ - key: "init", - value: function() { - e.types = { - avc1: [], - avcC: [], - btrt: [], - dinf: [], - dref: [], - esds: [], - ftyp: [], - hdlr: [], - mdat: [], - mdhd: [], - mdia: [], - mfhd: [], - minf: [], - moof: [], - moov: [], - mp4a: [], - mvex: [], - mvhd: [], - sdtp: [], - stbl: [], - stco: [], - stsc: [], - stsd: [], - stsz: [], - stts: [], - tfdt: [], - tfhd: [], - traf: [], - trak: [], - trun: [], - trex: [], - tkhd: [], - vmhd: [], - smhd: [], - ".mp3": [] - }; - for (var t in e.types) e.types.hasOwnProperty(t) && (e.types[t] = [t.charCodeAt(0), t.charCodeAt(1), t.charCodeAt(2), t.charCodeAt(3)]); - var n = e.constants = {}; - n.FTYP = new Uint8Array([105, 115, 111, 109, 0, 0, 0, 1, 105, 115, 111, 109, 97, 118, 99, 49]), n.STSD_PREFIX = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1]), n.STTS = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]), n.STSC = n.STCO = n.STTS, n.STSZ = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), n.HDLR_VIDEO = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 118, 105, 100, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 105, 100, 101, 111, 72, 97, 110, 100, 108, 101, 114, 0]), n.HDLR_AUDIO = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 115, 111, 117, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 111, 117, 110, 100, 72, 97, 110, 100, 108, 101, 114, 0]), n.DREF = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12, 117, 114, 108, 32, 0, 0, 0, 1]), n.SMHD = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]), n.VMHD = new Uint8Array([0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]) - } - }, { - key: "box", - value: function(e) { - for (var t = 8, n = null, i = Array.prototype.slice.call(arguments, 1), r = i.length, s = 0; s < r; s++) t += i[s].byteLength; - n = new Uint8Array(t), n[0] = t >>> 24 & 255, n[1] = t >>> 16 & 255, n[2] = t >>> 8 & 255, n[3] = 255 & t, n.set(e, 4); - for (var a = 8, o = 0; o < r; o++) n.set(i[o], a), a += i[o].byteLength; - return n - } - }, { - key: "generateInitSegment", - value: function(t) { - var n = e.box(e.types.ftyp, e.constants.FTYP), - i = e.moov(t), - r = new Uint8Array(n.byteLength + i.byteLength); - return r.set(n, 0), r.set(i, n.byteLength), r - } - }, { - key: "moov", - value: function(t) { - var n = e.mvhd(t.timescale, t.duration), - i = e.trak(t), - r = e.mvex(t); - return e.box(e.types.moov, n, i, r) - } - }, { - key: "mvhd", - value: function(t, n) { - return e.box(e.types.mvhd, new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t >>> 24 & 255, t >>> 16 & 255, t >>> 8 & 255, 255 & t, n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, 255 & n, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255])) - } - }, { - key: "trak", - value: function(t) { - return e.box(e.types.trak, e.tkhd(t), e.mdia(t)) - } - }, { - key: "tkhd", - value: function(t) { - var n = t.id, - i = t.duration, - r = t.presentWidth, - s = t.presentHeight; - return e.box(e.types.tkhd, new Uint8Array([0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, 255 & n, 0, 0, 0, 0, i >>> 24 & 255, i >>> 16 & 255, i >>> 8 & 255, 255 & i, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, r >>> 8 & 255, 255 & r, 0, 0, s >>> 8 & 255, 255 & s, 0, 0])) - } - }, { - key: "mdia", - value: function(t) { - return e.box(e.types.mdia, e.mdhd(t), e.hdlr(t), e.minf(t)) - } - }, { - key: "mdhd", - value: function(t) { - var n = t.timescale, - i = t.duration; - return e.box(e.types.mdhd, new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, 255 & n, i >>> 24 & 255, i >>> 16 & 255, i >>> 8 & 255, 255 & i, 85, 196, 0, 0])) - } - }, { - key: "hdlr", - value: function(t) { - var n = null; - return n = "audio" === t.type ? e.constants.HDLR_AUDIO : e.constants.HDLR_VIDEO, e.box(e.types.hdlr, n) - } - }, { - key: "minf", - value: function(t) { - var n = null; - return n = "audio" === t.type ? e.box(e.types.smhd, e.constants.SMHD) : e.box(e.types.vmhd, e.constants.VMHD), e.box(e.types.minf, n, e.dinf(), e.stbl(t)) - } - }, { - key: "dinf", - value: function() { - return e.box(e.types.dinf, e.box(e.types.dref, e.constants.DREF)) - } - }, { - key: "stbl", - value: function(t) { - return e.box(e.types.stbl, e.stsd(t), e.box(e.types.stts, e.constants.STTS), e.box(e.types.stsc, e.constants.STSC), e.box(e.types.stsz, e.constants.STSZ), e.box(e.types.stco, e.constants.STCO)) - } - }, { - key: "stsd", - value: function(t) { - return "audio" === t.type ? "mp3" === t.codec ? e.box(e.types.stsd, e.constants.STSD_PREFIX, e.mp3(t)) : e.box(e.types.stsd, e.constants.STSD_PREFIX, e.mp4a(t)) : e.box(e.types.stsd, e.constants.STSD_PREFIX, e.avc1(t)) - } - }, { - key: "mp3", - value: function(t) { - var n = t.channelCount, - i = t.audioSampleRate, - r = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, n, 0, 16, 0, 0, 0, 0, i >>> 8 & 255, 255 & i, 0, 0]); - return e.box(e.types[".mp3"], r) - } - }, { - key: "mp4a", - value: function(t) { - var n = t.channelCount, - i = t.audioSampleRate, - r = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, n, 0, 16, 0, 0, 0, 0, i >>> 8 & 255, 255 & i, 0, 0]); - return e.box(e.types.mp4a, r, e.esds(t)) - } - }, { - key: "esds", - value: function(t) { - var n = t.config || [], - i = n.length, - r = new Uint8Array([0, 0, 0, 0, 3, 23 + i, 0, 1, 0, 4, 15 + i, 64, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5].concat([i]).concat(n).concat([6, 1, 2])); - return e.box(e.types.esds, r) - } - }, { - key: "avc1", - value: function(t) { - var n = t.avcc, - i = t.codecWidth, - r = t.codecHeight, - s = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i >>> 8 & 255, 255 & i, r >>> 8 & 255, 255 & r, 0, 72, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 1, 10, 120, 113, 113, 47, 102, 108, 118, 46, 106, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 255, 255]); - return e.box(e.types.avc1, s, e.box(e.types.avcC, n)) - } - }, { - key: "mvex", - value: function(t) { - return e.box(e.types.mvex, e.trex(t)) - } - }, { - key: "trex", - value: function(t) { - var n = t.id, - i = new Uint8Array([0, 0, 0, 0, n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, 255 & n, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]); - return e.box(e.types.trex, i) - } - }, { - key: "moof", - value: function(t, n) { - return e.box(e.types.moof, e.mfhd(t.sequenceNumber), e.traf(t, n)) - } - }, { - key: "mfhd", - value: function(t) { - var n = new Uint8Array([0, 0, 0, 0, t >>> 24 & 255, t >>> 16 & 255, t >>> 8 & 255, 255 & t]); - return e.box(e.types.mfhd, n) - } - }, { - key: "traf", - value: function(t, n) { - var i = t.id, - r = e.box(e.types.tfhd, new Uint8Array([0, 0, 0, 0, i >>> 24 & 255, i >>> 16 & 255, i >>> 8 & 255, 255 & i])), - s = e.box(e.types.tfdt, new Uint8Array([0, 0, 0, 0, n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, 255 & n])), - a = e.sdtp(t), - o = e.trun(t, a.byteLength + 16 + 16 + 8 + 16 + 8 + 8); - return e.box(e.types.traf, r, s, o, a) - } - }, { - key: "sdtp", - value: function(t) { - for (var n = t.samples || [], i = n.length, r = new Uint8Array(4 + i), s = 0; s < i; s++) { - var a = n[s].flags; - r[s + 4] = a.isLeading << 6 | a.dependsOn << 4 | a.isDependedOn << 2 | a.hasRedundancy - } - return e.box(e.types.sdtp, r) - } - }, { - key: "trun", - value: function(t, n) { - var i = t.samples || [], - r = i.length, - s = 12 + 16 * r, - a = new Uint8Array(s); - n += 8 + s, a.set([0, 0, 15, 1, r >>> 24 & 255, r >>> 16 & 255, r >>> 8 & 255, 255 & r, n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, 255 & n], 0); - for (var o = 0; o < r; o++) { - var u = i[o].duration, - l = i[o].size, - d = i[o].flags, - h = i[o].cts; - a.set([u >>> 24 & 255, u >>> 16 & 255, u >>> 8 & 255, 255 & u, l >>> 24 & 255, l >>> 16 & 255, l >>> 8 & 255, 255 & l, d.isLeading << 2 | d.dependsOn, d.isDependedOn << 6 | d.hasRedundancy << 4 | d.isNonSync, 0, 0, h >>> 24 & 255, h >>> 16 & 255, h >>> 8 & 255, 255 & h], 12 + 16 * o) - } - return e.box(e.types.trun, a) - } - }, { - key: "mdat", - value: function(t) { - return e.box(e.types.mdat, t) - } - }]), e - }(); - s.init(), n.default = s - }, {}], - 38: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var s = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - a = e("../utils/logger.js"), - o = i(a), - u = e("./mp4-generator.js"), - l = i(u), - d = e("./aac-silent.js"), - h = i(d), - f = e("../utils/browser.js"), - c = i(f), - _ = e("../core/media-segment-info.js"), - m = e("../utils/exception.js"), - p = function() { - function e(t) { - r(this, e), this.TAG = "MP4Remuxer", this._config = t, this._isLive = !0 === t.isLive, this._dtsBase = -1, this._dtsBaseInited = !1, this._audioDtsBase = 1 / 0, this._videoDtsBase = 1 / 0, this._audioNextDts = void 0, this._videoNextDts = void 0, this._audioStashedLastSample = null, this._videoStashedLastSample = null, this._audioMeta = null, this._videoMeta = null, this._audioSegmentInfoList = new _.MediaSegmentInfoList("audio"), this._videoSegmentInfoList = new _.MediaSegmentInfoList("video"), this._onInitSegment = null, this._onMediaSegment = null, this._forceFirstIDR = !(!c.default.chrome || !(c.default.version.major < 50 || 50 === c.default.version.major && c.default.version.build < 2661)), this._fillSilentAfterSeek = c.default.msedge || c.default.msie, this._mp3UseMpegAudio = !c.default.firefox, this._fillAudioTimestampGap = this._config.fixAudioTimestampGap - } - return s(e, [{ - key: "destroy", - value: function() { - this._dtsBase = -1, this._dtsBaseInited = !1, this._audioMeta = null, this._videoMeta = null, this._audioSegmentInfoList.clear(), this._audioSegmentInfoList = null, this._videoSegmentInfoList.clear(), this._videoSegmentInfoList = null, this._onInitSegment = null, this._onMediaSegment = null - } - }, { - key: "bindDataSource", - value: function(e) { - return e.onDataAvailable = this.remux.bind(this), e.onTrackMetadata = this._onTrackMetadataReceived.bind(this), this - } - }, { - key: "insertDiscontinuity", - value: function() { - this._audioNextDts = this._videoNextDts = void 0 - } - }, { - key: "seek", - value: function(e) { - this._audioStashedLastSample = null, this._videoStashedLastSample = null, this._videoSegmentInfoList.clear(), this._audioSegmentInfoList.clear() - } - }, { - key: "remux", - value: function(e, t) { - if (!this._onMediaSegment) throw new m.IllegalStateException("MP4Remuxer: onMediaSegment callback must be specificed!"); - this._dtsBaseInited || this._calculateDtsBase(e, t), this._remuxVideo(t), this._remuxAudio(e) - } - }, { - key: "_onTrackMetadataReceived", - value: function(e, t) { - var n = null, - i = "mp4", - r = t.codec; - if ("audio" === e) this._audioMeta = t, "mp3" === t.codec && this._mp3UseMpegAudio ? (i = "mpeg", r = "", n = new Uint8Array) : n = l.default.generateInitSegment(t); - else { - if ("video" !== e) return; - this._videoMeta = t, n = l.default.generateInitSegment(t) - } - if (!this._onInitSegment) throw new m.IllegalStateException("MP4Remuxer: onInitSegment callback must be specified!"); - this._onInitSegment(e, { - type: e, - data: n.buffer, - codec: r, - container: e + "/" + i, - mediaDuration: t.duration - }) - } - }, { - key: "_calculateDtsBase", - value: function(e, t) { - this._dtsBaseInited || (e.samples && e.samples.length && (this._audioDtsBase = e.samples[0].dts), t.samples && t.samples.length && (this._videoDtsBase = t.samples[0].dts), this._dtsBase = Math.min(this._audioDtsBase, this._videoDtsBase), this._dtsBaseInited = !0) - } - }, { - key: "flushStashedSamples", - value: function() { - var e = this._videoStashedLastSample, - t = this._audioStashedLastSample, - n = { - type: "video", - id: 1, - sequenceNumber: 0, - samples: [], - length: 0 - }; - null != e && (n.samples.push(e), n.length = e.length); - var i = { - type: "audio", - id: 2, - sequenceNumber: 0, - samples: [], - length: 0 - }; - null != t && (i.samples.push(t), i.length = t.length), this._videoStashedLastSample = null, this._audioStashedLastSample = null, this._remuxVideo(n, !0), this._remuxAudio(i, !0) - } - }, { - key: "_remuxAudio", - value: function(e, t) { - if (null != this._audioMeta) { - var n = e, - i = n.samples, - r = void 0, - s = -1, - a = -1, - u = this._audioMeta.refSampleDuration, - d = "mp3" === this._audioMeta.codec && this._mp3UseMpegAudio, - f = this._dtsBaseInited && void 0 === this._audioNextDts, - m = !1; - if (i && 0 !== i.length && (1 !== i.length || t)) { - var p = 0, - v = null, - g = 0; - d ? (p = 0, g = n.length) : (p = 8, g = 8 + n.length); - var y = null; - if (i.length > 1 && (y = i.pop(), g -= y.length), null != this._audioStashedLastSample) { - var E = this._audioStashedLastSample; - this._audioStashedLastSample = null, i.unshift(E), g += E.length - } - null != y && (this._audioStashedLastSample = y); - var b = i[0].dts - this._dtsBase; - if (this._audioNextDts) r = b - this._audioNextDts; - else if (this._audioSegmentInfoList.isEmpty()) r = 0, this._fillSilentAfterSeek && !this._videoSegmentInfoList.isEmpty() && "mp3" !== this._audioMeta.originalCodec && (m = !0); - else { - var S = this._audioSegmentInfoList.getLastSampleBefore(b); - if (null != S) { - var k = b - (S.originalDts + S.duration); - k <= 3 && (k = 0); - var L = S.dts + S.duration + k; - r = b - L - } else r = 0 - } - if (m) { - var w = b - r, - R = this._videoSegmentInfoList.getLastSegmentBefore(b); - if (null != R && R.beginDts < w) { - var A = h.default.getSilentFrame(this._audioMeta.originalCodec, this._audioMeta.channelCount); - if (A) { - var O = R.beginDts, - T = w - R.beginDts; - o.default.v(this.TAG, "InsertPrefixSilentAudio: dts: " + O + ", duration: " + T), i.unshift({ - unit: A, - dts: O, - pts: O - }), g += A.byteLength - } - } else m = !1 - } - for (var C = [], I = 0; I < i.length; I++) { - var x = i[I], - M = x.unit, - D = x.dts - this._dtsBase, - B = D - r; - 1 === s && (s = B); - var j = 0; - if (I !== i.length - 1) { - j = i[I + 1].dts - this._dtsBase - r - B - } else if (null != y) { - var P = y.dts - this._dtsBase - r; - j = P - B - } else j = C.length >= 1 ? C[C.length - 1].duration : Math.floor(u); - var U = !1, - N = null; - if (j > 1.5 * u && "mp3" !== this._audioMeta.codec && this._fillAudioTimestampGap && !c.default.safari) { - U = !0; - var F = Math.abs(j - u), - G = Math.ceil(F / u), - V = B + u; - o.default.w(this.TAG, "Large audio timestamp gap detected, may cause AV sync to drift. Silent frames will be generated to avoid unsync.\ndts: " + (B + j) + " ms, expected: " + (B + Math.round(u)) + " ms, delta: " + Math.round(F) + " ms, generate: " + G + " frames"); - var z = h.default.getSilentFrame(this._audioMeta.originalCodec, this._audioMeta.channelCount); - null == z && (o.default.w(this.TAG, "Unable to generate silent frame for " + this._audioMeta.originalCodec + " with " + this._audioMeta.channelCount + " channels, repeat last frame"), z = M), N = []; - for (var H = 0; H < G; H++) { - var K = Math.round(V); - if (N.length > 0) { - var q = N[N.length - 1]; - q.duration = K - q.dts - } - var W = { - dts: K, - pts: K, - cts: 0, - unit: z, - size: z.byteLength, - duration: 0, - originalDts: D, - flags: { - isLeading: 0, - dependsOn: 1, - isDependedOn: 0, - hasRedundancy: 0 - } - }; - N.push(W), g += M.byteLength, V += u - } - var X = N[N.length - 1]; - X.duration = B + j - X.dts, j = Math.round(u) - } - C.push({ - dts: B, - pts: B, - cts: 0, - unit: x.unit, - size: x.unit.byteLength, - duration: j, - originalDts: D, - flags: { - isLeading: 0, - dependsOn: 1, - isDependedOn: 0, - hasRedundancy: 0 - } - }), U && C.push.apply(C, N) - } - d ? v = new Uint8Array(g) : (v = new Uint8Array(g), v[0] = g >>> 24 & 255, v[1] = g >>> 16 & 255, v[2] = g >>> 8 & 255, v[3] = 255 & g, v.set(l.default.types.mdat, 4)); - for (var Y = 0; Y < C.length; Y++) { - var Z = C[Y].unit; - v.set(Z, p), p += Z.byteLength - } - var Q = C[C.length - 1]; - a = Q.dts + Q.duration, this._audioNextDts = a; - var J = new _.MediaSegmentInfo; - J.beginDts = s, J.endDts = a, J.beginPts = s, J.endPts = a, J.originalBeginDts = C[0].originalDts, J.originalEndDts = Q.originalDts + Q.duration, J.firstSample = new _.SampleInfo(C[0].dts, C[0].pts, C[0].duration, C[0].originalDts, !1), J.lastSample = new _.SampleInfo(Q.dts, Q.pts, Q.duration, Q.originalDts, !1), this._isLive || this._audioSegmentInfoList.append(J), n.samples = C, n.sequenceNumber++; - var $ = null; - $ = d ? new Uint8Array : l.default.moof(n, s), n.samples = [], n.length = 0; - var ee = { - type: "audio", - data: this._mergeBoxes($, v).buffer, - sampleCount: C.length, - info: J - }; - d && f && (ee.timestampOffset = s), this._onMediaSegment("audio", ee) - } - } - } - }, { - key: "_remuxVideo", - value: function(e, t) { - if (null != this._videoMeta) { - var n = e, - i = n.samples, - r = void 0, - s = -1, - a = -1, - o = -1, - u = -1; - if (i && 0 !== i.length && (1 !== i.length || t)) { - var d = 8, - h = null, - f = 8 + e.length, - c = null; - if (i.length > 1 && (c = i.pop(), f -= c.length), null != this._videoStashedLastSample) { - var m = this._videoStashedLastSample; - this._videoStashedLastSample = null, i.unshift(m), f += m.length - } - null != c && (this._videoStashedLastSample = c); - var p = i[0].dts - this._dtsBase; - if (this._videoNextDts) r = p - this._videoNextDts; - else if (this._videoSegmentInfoList.isEmpty()) r = 0; - else { - var v = this._videoSegmentInfoList.getLastSampleBefore(p); - if (null != v) { - var g = p - (v.originalDts + v.duration); - g <= 3 && (g = 0); - var y = v.dts + v.duration + g; - r = p - y - } else r = 0 - } - for (var E = new _.MediaSegmentInfo, b = [], S = 0; S < i.length; S++) { - var k = i[S], - L = k.dts - this._dtsBase, - w = k.isKeyframe, - R = L - r, - A = k.cts, - O = R + A; - 1 === s && (s = R, o = O); - var T = 0; - if (S !== i.length - 1) { - T = i[S + 1].dts - this._dtsBase - r - R - } else if (null != c) { - var C = c.dts - this._dtsBase - r; - T = C - R - } else T = b.length >= 1 ? b[b.length - 1].duration : Math.floor(this._videoMeta.refSampleDuration); - if (w) { - var I = new _.SampleInfo(R, O, T, k.dts, !0); - I.fileposition = k.fileposition, E.appendSyncPoint(I) - } - b.push({ - dts: R, - pts: O, - cts: A, - units: k.units, - size: k.length, - isKeyframe: w, - duration: T, - originalDts: L, - flags: { - isLeading: 0, - dependsOn: w ? 2 : 1, - isDependedOn: w ? 1 : 0, - hasRedundancy: 0, - isNonSync: w ? 0 : 1 - } - }) - } - h = new Uint8Array(f), h[0] = f >>> 24 & 255, h[1] = f >>> 16 & 255, h[2] = f >>> 8 & 255, h[3] = 255 & f, h.set(l.default.types.mdat, 4); - for (var x = 0; x < b.length; x++) - for (var M = b[x].units; M.length;) { - var D = M.shift(), - B = D.data; - h.set(B, d), d += B.byteLength - } - var j = b[b.length - 1]; - if (a = j.dts + j.duration, u = j.pts + j.duration, this._videoNextDts = a, E.beginDts = s, E.endDts = a, E.beginPts = o, E.endPts = u, E.originalBeginDts = b[0].originalDts, E.originalEndDts = j.originalDts + j.duration, E.firstSample = new _.SampleInfo(b[0].dts, b[0].pts, b[0].duration, b[0].originalDts, b[0].isKeyframe), E.lastSample = new _.SampleInfo(j.dts, j.pts, j.duration, j.originalDts, j.isKeyframe), this._isLive || this._videoSegmentInfoList.append(E), n.samples = b, n.sequenceNumber++, this._forceFirstIDR) { - var P = b[0].flags; - P.dependsOn = 2, P.isNonSync = 0 - } - var U = l.default.moof(n, s); - n.samples = [], n.length = 0, this._onMediaSegment("video", { - type: "video", - data: this._mergeBoxes(U, h).buffer, - sampleCount: b.length, - info: E - }) - } - } - } - }, { - key: "_mergeBoxes", - value: function(e, t) { - var n = new Uint8Array(e.byteLength + t.byteLength); - return n.set(e, 0), n.set(t, e.byteLength), n - } - }, { - key: "onInitSegment", - get: function() { - return this._onInitSegment - }, - set: function(e) { - this._onInitSegment = e - } - }, { - key: "onMediaSegment", - get: function() { - return this._onMediaSegment - }, - set: function(e) { - this._onMediaSegment = e - } - }]), e - }(); - n.default = p - }, { - "../core/media-segment-info.js": 8, - "../utils/browser.js": 39, - "../utils/exception.js": 40, - "../utils/logger.js": 41, - "./aac-silent.js": 36, - "./mp4-generator.js": 37 - }], - 39: [function(e, t, n) { - "use strict"; - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var i = {}; - ! function() { - var e = self.navigator.userAgent.toLowerCase(), - t = /(edge)\/([\w.]+)/.exec(e) || /(opr)[\/]([\w.]+)/.exec(e) || /(chrome)[ \/]([\w.]+)/.exec(e) || /(iemobile)[\/]([\w.]+)/.exec(e) || /(version)(applewebkit)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec(e) || /(webkit)[ \/]([\w.]+).*(version)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec(e) || /(webkit)[ \/]([\w.]+)/.exec(e) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e) || /(msie) ([\w.]+)/.exec(e) || e.indexOf("trident") >= 0 && /(rv)(?::| )([\w.]+)/.exec(e) || e.indexOf("compatible") < 0 && /(firefox)[ \/]([\w.]+)/.exec(e) || [], - n = /(ipad)/.exec(e) || /(ipod)/.exec(e) || /(windows phone)/.exec(e) || /(iphone)/.exec(e) || /(kindle)/.exec(e) || /(android)/.exec(e) || /(windows)/.exec(e) || /(mac)/.exec(e) || /(linux)/.exec(e) || /(cros)/.exec(e) || [], - r = { - browser: t[5] || t[3] || t[1] || "", - version: t[2] || t[4] || "0", - majorVersion: t[4] || t[2] || "0", - platform: n[0] || "" - }, - s = {}; - if (r.browser) { - s[r.browser] = !0; - var a = r.majorVersion.split("."); - s.version = { - major: parseInt(r.majorVersion, 10), - string: r.version - }, a.length > 1 && (s.version.minor = parseInt(a[1], 10)), a.length > 2 && (s.version.build = parseInt(a[2], 10)) - } - r.platform && (s[r.platform] = !0), (s.chrome || s.opr || s.safari) && (s.webkit = !0), (s.rv || s.iemobile) && (s.rv && delete s.rv, r.browser = "msie", s.msie = !0), s.edge && (delete s.edge, r.browser = "msedge", s.msedge = !0), s.opr && (r.browser = "opera", s.opera = !0), s.safari && s.android && (r.browser = "android", s.android = !0), s.name = r.browser, s.platform = r.platform; - for (var o in i) i.hasOwnProperty(o) && delete i[o]; - Object.assign(i, s) - }(), n.default = i - }, {}], - 40: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !t || "object" != typeof t && "function" != typeof t ? e : t - } - - function r(e, t) { - if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); - e.prototype = Object.create(t && t.prototype, { - constructor: { - value: e, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) - } - - function s(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var a = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - o = n.RuntimeException = function() { - function e(t) { - s(this, e), this._message = t - } - return a(e, [{ - key: "toString", - value: function() { - return this.name + ": " + this.message - } - }, { - key: "name", - get: function() { - return "RuntimeException" - } - }, { - key: "message", - get: function() { - return this._message - } - }]), e - }(); - n.IllegalStateException = function(e) { - function t(e) { - return s(this, t), i(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e)) - } - return r(t, e), a(t, [{ - key: "name", - get: function() { - return "IllegalStateException" - } - }]), t - }(o), n.InvalidArgumentException = function(e) { - function t(e) { - return s(this, t), i(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e)) - } - return r(t, e), a(t, [{ - key: "name", - get: function() { - return "InvalidArgumentException" - } - }]), t - }(o), n.NotImplementedException = function(e) { - function t(e) { - return s(this, t), i(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e)) - } - return r(t, e), a(t, [{ - key: "name", - get: function() { - return "NotImplementedException" - } - }]), t - }(o) - }, {}], - 41: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = e("events"), - a = function(e) { - return e && e.__esModule ? e : { - default: e - } - }(s), - o = function() { - function e() { - i(this, e) - } - return r(e, null, [{ - key: "e", - value: function(t, n) { - t && !e.FORCE_GLOBAL_TAG || (t = e.GLOBAL_TAG); - var i = "[" + t + "] > " + n; - e.ENABLE_CALLBACK && e.emitter.emit("log", "error", i), e.ENABLE_ERROR && (console.error ? console.error(i) : console.warn ? console.warn(i) : console.log(i)) - } - }, { - key: "i", - value: function(t, n) { - t && !e.FORCE_GLOBAL_TAG || (t = e.GLOBAL_TAG); - var i = "[" + t + "] > " + n; - e.ENABLE_CALLBACK && e.emitter.emit("log", "info", i), e.ENABLE_INFO && (console.info ? console.info(i) : console.log(i)) - } - }, { - key: "w", - value: function(t, n) { - t && !e.FORCE_GLOBAL_TAG || (t = e.GLOBAL_TAG); - var i = "[" + t + "] > " + n; - e.ENABLE_CALLBACK && e.emitter.emit("log", "warn", i), e.ENABLE_WARN && (console.warn ? console.warn(i) : console.log(i)) - } - }, { - key: "d", - value: function(t, n) { - t && !e.FORCE_GLOBAL_TAG || (t = e.GLOBAL_TAG); - var i = "[" + t + "] > " + n; - e.ENABLE_CALLBACK && e.emitter.emit("log", "debug", i), e.ENABLE_DEBUG && (console.debug ? console.debug(i) : console.log(i)) - } - }, { - key: "v", - value: function(t, n) { - t && !e.FORCE_GLOBAL_TAG || (t = e.GLOBAL_TAG); - var i = "[" + t + "] > " + n; - e.ENABLE_CALLBACK && e.emitter.emit("log", "verbose", i), e.ENABLE_VERBOSE && console.log(i) - } - }]), e - }(); - o.GLOBAL_TAG = "flv.js", o.FORCE_GLOBAL_TAG = !1, o.ENABLE_ERROR = !0, o.ENABLE_INFO = !0, o.ENABLE_WARN = !0, o.ENABLE_DEBUG = !0, o.ENABLE_VERBOSE = !0, o.ENABLE_CALLBACK = !1, o.emitter = new a.default, n.default = o - }, { - events: 2 - }], - 42: [function(e, t, n) { - "use strict"; - - function i(e) { - return e && e.__esModule ? e : { - default: e - } - } - - function r(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var s = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - a = e("events"), - o = i(a), - u = e("./logger.js"), - l = i(u), - d = function() { - function e() { - r(this, e) - } - return s(e, null, [{ - key: "getConfig", - value: function() { - return { - globalTag: l.default.GLOBAL_TAG, - forceGlobalTag: l.default.FORCE_GLOBAL_TAG, - enableVerbose: l.default.ENABLE_VERBOSE, - enableDebug: l.default.ENABLE_DEBUG, - enableInfo: l.default.ENABLE_INFO, - enableWarn: l.default.ENABLE_WARN, - enableError: l.default.ENABLE_ERROR, - enableCallback: l.default.ENABLE_CALLBACK - } - } - }, { - key: "applyConfig", - value: function(e) { - l.default.GLOBAL_TAG = e.globalTag, l.default.FORCE_GLOBAL_TAG = e.forceGlobalTag, l.default.ENABLE_VERBOSE = e.enableVerbose, l.default.ENABLE_DEBUG = e.enableDebug, l.default.ENABLE_INFO = e.enableInfo, l.default.ENABLE_WARN = e.enableWarn, l.default.ENABLE_ERROR = e.enableError, l.default.ENABLE_CALLBACK = e.enableCallback - } - }, { - key: "_notifyChange", - value: function() { - var t = e.emitter; - if (t.listenerCount("change") > 0) { - var n = e.getConfig(); - t.emit("change", n) - } - } - }, { - key: "registerListener", - value: function(t) { - e.emitter.addListener("change", t) - } - }, { - key: "removeListener", - value: function(t) { - e.emitter.removeListener("change", t) - } - }, { - key: "addLogListener", - value: function(t) { - l.default.emitter.addListener("log", t), l.default.emitter.listenerCount("log") > 0 && (l.default.ENABLE_CALLBACK = !0, e._notifyChange()) - } - }, { - key: "removeLogListener", - value: function(t) { - l.default.emitter.removeListener("log", t), 0 === l.default.emitter.listenerCount("log") && (l.default.ENABLE_CALLBACK = !1, e._notifyChange()) - } - }, { - key: "forceGlobalTag", - get: function() { - return l.default.FORCE_GLOBAL_TAG - }, - set: function(t) { - l.default.FORCE_GLOBAL_TAG = t, e._notifyChange() - } - }, { - key: "globalTag", - get: function() { - return l.default.GLOBAL_TAG - }, - set: function(t) { - l.default.GLOBAL_TAG = t, e._notifyChange() - } - }, { - key: "enableAll", - get: function() { - return l.default.ENABLE_VERBOSE && l.default.ENABLE_DEBUG && l.default.ENABLE_INFO && l.default.ENABLE_WARN && l.default.ENABLE_ERROR - }, - set: function(t) { - l.default.ENABLE_VERBOSE = t, l.default.ENABLE_DEBUG = t, l.default.ENABLE_INFO = t, l.default.ENABLE_WARN = t, l.default.ENABLE_ERROR = t, e._notifyChange() - } - }, { - key: "enableDebug", - get: function() { - return l.default.ENABLE_DEBUG - }, - set: function(t) { - l.default.ENABLE_DEBUG = t, e._notifyChange() - } - }, { - key: "enableVerbose", - get: function() { - return l.default.ENABLE_VERBOSE - }, - set: function(t) { - l.default.ENABLE_VERBOSE = t, e._notifyChange() - } - }, { - key: "enableInfo", - get: function() { - return l.default.ENABLE_INFO - }, - set: function(t) { - l.default.ENABLE_INFO = t, e._notifyChange() - } - }, { - key: "enableWarn", - get: function() { - return l.default.ENABLE_WARN - }, - set: function(t) { - l.default.ENABLE_WARN = t, e._notifyChange() - } - }, { - key: "enableError", - get: function() { - return l.default.ENABLE_ERROR - }, - set: function(t) { - l.default.ENABLE_ERROR = t, e._notifyChange() - } - }]), e - }(); - d.emitter = new o.default, n.default = d - }, { - "./logger.js": 41, - events: 2 - }], - 43: [function(e, t, n) { - "use strict"; - - function i(e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }); - var r = function() { - function e(e, t) { - for (var n = 0; n < t.length; n++) { - var i = t[n]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) - } - } - return function(t, n, i) { - return n && e(t.prototype, n), i && e(t, i), t - } - }(), - s = function() { - function t() { - i(this, t) - } - return r(t, null, [{ - key: "install", - value: function() { - Object.setPrototypeOf = Object.setPrototypeOf || function(e, t) { - return e.__proto__ = t, e - }, Object.assign = Object.assign || function(e) { - if (void 0 === e || null === e) throw new TypeError("Cannot convert undefined or null to object"); - for (var t = Object(e), n = 1; n < arguments.length; n++) { - var i = arguments[n]; - if (void 0 !== i && null !== i) - for (var r in i) i.hasOwnProperty(r) && (t[r] = i[r]) - } - return t - }, "function" != typeof self.Promise && e("es6-promise").polyfill() - } - }]), t - }(); - s.install(), n.default = s - }, { - "es6-promise": 1 - }], - 44: [function(e, t, n) { - "use strict"; - - function i(e, t, n) { - var i = e; - if (t + n < i.length) { - for (; n--;) - if (128 != (192 & i[++t])) return !1; - return !0 - } - return !1 - } - - function r(e) { - for (var t = [], n = e, r = 0, s = e.length; r < s;) - if (n[r] < 128) t.push(String.fromCharCode(n[r])), ++r; - else { - if (n[r] < 192); - else if (n[r] < 224) { - if (i(n, r, 1)) { - var a = (31 & n[r]) << 6 | 63 & n[r + 1]; - if (a >= 128) { - t.push(String.fromCharCode(65535 & a)), r += 2; - continue - } - } - } else if (n[r] < 240) { - if (i(n, r, 2)) { - var o = (15 & n[r]) << 12 | (63 & n[r + 1]) << 6 | 63 & n[r + 2]; - if (o >= 2048 && 55296 != (63488 & o)) { - t.push(String.fromCharCode(65535 & o)), r += 3; - continue - } - } - } else if (n[r] < 248 && i(n, r, 3)) { - var u = (7 & n[r]) << 18 | (63 & n[r + 1]) << 12 | (63 & n[r + 2]) << 6 | 63 & n[r + 3]; - if (u > 65536 && u < 1114112) { - u -= 65536, t.push(String.fromCharCode(u >>> 10 | 55296)), t.push(String.fromCharCode(1023 & u | 56320)), r += 4; - continue - } - } - t.push(String.fromCharCode(65533)), ++r - } return t.join("") - } - Object.defineProperty(n, "__esModule", { - value: !0 - }), n.default = r - }, {}] - }, {}, [21])(21) -}); -//# sourceMappingURL=flv.min.js.map \ No newline at end of file +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.flvjs=e()}}(function(){var e;return function e(t,n,i){function r(a,o){if(!n[a]){if(!t[a]){var u="function"==typeof require&&require;if(!o&&u)return u(a,!0);if(s)return s(a,!0);var l=new Error("Cannot find module '"+a+"'");throw l.code="MODULE_NOT_FOUND",l}var d=n[a]={exports:{}};t[a][0].call(d.exports,function(e){var n=t[a][1][e];return r(n||e)},d,d.exports,e,t,n,i)}return n[a].exports}for(var s="function"==typeof require&&require,a=0;a0&&this._events[e].length>n&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},i.prototype.on=i.prototype.addListener,i.prototype.once=function(e,t){function n(){this.removeListener(e,n),i||(i=!0,t.apply(this,arguments))}if(!r(t))throw TypeError("listener must be a function");var i=!1;return n.listener=t,this.on(e,n),this},i.prototype.removeListener=function(e,t){var n,i,s,o;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(n=this._events[e],s=n.length,i=-1,n===t||r(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(a(n)){for(o=s;o-- >0;)if(n[o]===t||n[o].listener&&n[o].listener===t){i=o;break}if(i<0)return this;1===n.length?(n.length=0,delete this._events[e]):n.splice(i,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},i.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[e],r(n))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},i.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},i.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},i.listenerCount=function(e,t){return e.listenerCount(t)}},{}],3:[function(e,t,n){function i(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function s(e){if(h===setTimeout)return setTimeout(e,0);if((h===i||!h)&&setTimeout)return h=setTimeout,setTimeout(e,0);try{return h(e,0)}catch(t){try{return h.call(null,e,0)}catch(t){return h.call(this,e,0)}}}function a(e){if(f===clearTimeout)return clearTimeout(e);if((f===r||!f)&&clearTimeout)return f=clearTimeout,clearTimeout(e);try{return f(e)}catch(t){try{return f.call(null,e)}catch(t){return f.call(this,e)}}}function o(){p&&_&&(p=!1,_.length?m=_.concat(m):v=-1,m.length&&u())}function u(){if(!p){var e=s(o);p=!0;for(var t=m.length;t;){for(_=m,m=[];++v1)for(var n=1;n=e[r]&&t0&&e[0].originalDts=t[r].dts&&et[i].lastSample.originalDts&&e=t[i].lastSample.originalDts&&(i===t.length-1||i0&&(r=this._searchNearestSegmentBefore(n.originalBeginDts)+1),this._lastAppendLocation=r,this._list.splice(r,0,n)}},{key:"getLastSegmentBefore",value:function(e){var t=this._searchNearestSegmentBefore(e);return t>=0?this._list[t]:null}},{key:"getLastSampleBefore",value:function(e){var t=this.getLastSegmentBefore(e);return null!=t?t.lastSample:null}},{key:"getLastSyncPointBefore",value:function(e){for(var t=this._searchNearestSegmentBefore(e),n=this._list[t].syncPoints;0===n.length&&t>0;)t--,n=this._list[t].syncPoints;return n.length>0?n[n.length-1]:null}},{key:"type",get:function(){return this._type}},{key:"length",get:function(){return this._list.length}}]),e}()},{}],9:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var s=function(){function e(e,t){for(var n=0;n0&&(i+=";codecs="+n.codec);var r=!1;if(l.default.v(this.TAG,"Received Initialization Segment, mimeType: "+i),this._lastInitSegments[n.type]=n,i!==this._mimeTypes[n.type]){if(this._mimeTypes[n.type])l.default.v(this.TAG,"Notice: "+n.type+" mimeType changed, origin: "+this._mimeTypes[n.type]+", target: "+i);else{r=!0;try{var s=this._sourceBuffers[n.type]=this._mediaSource.addSourceBuffer(i);s.addEventListener("error",this.e.onSourceBufferError),s.addEventListener("updateend",this.e.onSourceBufferUpdateEnd)}catch(e){return l.default.e(this.TAG,e.message),void this._emitter.emit(c.default.ERROR,{code:e.code,msg:e.message})}}this._mimeTypes[n.type]=i}t||this._pendingSegments[n.type].push(n),r||this._sourceBuffers[n.type]&&!this._sourceBuffers[n.type].updating&&this._doAppendSegments(),h.default.safari&&"audio/mpeg"===n.container&&n.mediaDuration>0&&(this._requireSetMediaDuration=!0,this._pendingMediaDuration=n.mediaDuration/1e3,this._updateMediaSourceDuration())}},{key:"appendMediaSegment",value:function(e){var t=e;this._pendingSegments[t.type].push(t),this._config.autoCleanupSourceBuffer&&this._needCleanupSourceBuffer()&&this._doCleanupSourceBuffer();var n=this._sourceBuffers[t.type];!n||n.updating||this._hasPendingRemoveRanges()||this._doAppendSegments()}},{key:"seek",value:function(e){for(var t in this._sourceBuffers)if(this._sourceBuffers[t]){var n=this._sourceBuffers[t];if("open"===this._mediaSource.readyState)try{n.abort()}catch(e){l.default.e(this.TAG,e.message)}this._idrList.clear();var i=this._pendingSegments[t];if(i.splice(0,i.length),"closed"!==this._mediaSource.readyState){for(var r=0;r=1&&e-i.start(0)>=this._config.autoCleanupMaxBackwardDuration)return!0}}return!1}},{key:"_doCleanupSourceBuffer",value:function(){var e=this._mediaElement.currentTime;for(var t in this._sourceBuffers){var n=this._sourceBuffers[t];if(n){for(var i=n.buffered,r=!1,s=0;s=this._config.autoCleanupMaxBackwardDuration){r=!0;var u=e-this._config.autoCleanupMinBackwardDuration;this._pendingRemoveRanges[t].push({start:a,end:u})}}else o0&&(isNaN(t)||n>t)&&(l.default.v(this.TAG,"Update MediaSource duration from "+t+" to "+n),this._mediaSource.duration=n),this._requireSetMediaDuration=!1,this._pendingMediaDuration=0}}},{key:"_doRemoveRanges",value:function(){for(var e in this._pendingRemoveRanges)if(this._sourceBuffers[e]&&!this._sourceBuffers[e].updating)for(var t=this._sourceBuffers[e],n=this._pendingRemoveRanges[e];n.length&&!t.updating;){var i=n.shift();t.remove(i.start,i.end)}}},{key:"_doAppendSegments",value:function(){var e=this._pendingSegments;for(var t in e)if(this._sourceBuffers[t]&&!this._sourceBuffers[t].updating&&e[t].length>0){var n=e[t].shift();if(n.timestampOffset){var i=this._sourceBuffers[t].timestampOffset,r=n.timestampOffset/1e3,s=Math.abs(i-r);s>.1&&(l.default.v(this.TAG,"Update MPEG audio timestampOffset from "+i+" to "+r),this._sourceBuffers[t].timestampOffset=r),delete n.timestampOffset}if(!n.data||0===n.data.byteLength)continue;try{this._sourceBuffers[t].appendBuffer(n.data),this._isBufferFull=!1,"video"===t&&n.hasOwnProperty("info")&&this._idrList.appendArray(n.info.syncPoints)}catch(e){this._pendingSegments[t].unshift(n),22===e.code?(this._isBufferFull||this._emitter.emit(c.default.BUFFER_FULL),this._isBufferFull=!0):(l.default.e(this.TAG,e.message),this._emitter.emit(c.default.ERROR,{code:e.code,msg:e.message}))}}}},{key:"_onSourceOpen",value:function(){if(l.default.v(this.TAG,"MediaSource onSourceOpen"),this._mediaSource.removeEventListener("sourceopen",this.e.onSourceOpen),this._pendingSourceBufferInit.length>0)for(var e=this._pendingSourceBufferInit;e.length;){var t=e.shift();this.appendInitSegment(t,!0)}this._hasPendingSegments()&&this._doAppendSegments(),this._emitter.emit(c.default.SOURCE_OPEN)}},{key:"_onSourceEnded",value:function(){l.default.v(this.TAG,"MediaSource onSourceEnded")}},{key:"_onSourceClose",value:function(){l.default.v(this.TAG,"MediaSource onSourceClose"),this._mediaSource&&null!=this.e&&(this._mediaSource.removeEventListener("sourceopen",this.e.onSourceOpen),this._mediaSource.removeEventListener("sourceended",this.e.onSourceEnded),this._mediaSource.removeEventListener("sourceclose",this.e.onSourceClose))}},{key:"_hasPendingSegments",value:function(){var e=this._pendingSegments;return e.video.length>0||e.audio.length>0}},{key:"_hasPendingRemoveRanges",value:function(){var e=this._pendingRemoveRanges;return e.video.length>0||e.audio.length>0}},{key:"_onSourceBufferUpdateEnd",value:function(){this._requireSetMediaDuration?this._updateMediaSourceDuration():this._hasPendingRemoveRanges()?this._doRemoveRanges():this._hasPendingSegments()?this._doAppendSegments():this._hasPendingEos&&this.endOfStream(),this._emitter.emit(c.default.UPDATE_END)}},{key:"_onSourceBufferError",value:function(e){l.default.e(this.TAG,"SourceBuffer Error: "+e)}}]),e}();n.default=p},{"../utils/browser.js":39,"../utils/exception.js":40,"../utils/logger.js":41,"./media-segment-info.js":8,"./mse-events.js":10,events:2}],10:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var i={ERROR:"error",SOURCE_OPEN:"source_open",UPDATE_END:"update_end",BUFFER_FULL:"buffer_full"};n.default=i},{}],11:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var s=function(){function e(e,t){for(var n=0;n0)this._demuxer.bindDataSource(this._ioctl),this._demuxer.timestampBase=this._mediaDataSource.segments[this._currentSegmentIndex].timestampBase,r=this._demuxer.parseChunks(e,t);else if((i=m.default.probe(e)).match){this._demuxer=new m.default(i,this._config),this._remuxer||(this._remuxer=new v.default(this._config));var s=this._mediaDataSource;void 0==s.duration||isNaN(s.duration)||(this._demuxer.overridedDuration=s.duration),"boolean"==typeof s.hasAudio&&(this._demuxer.overridedHasAudio=s.hasAudio),"boolean"==typeof s.hasVideo&&(this._demuxer.overridedHasVideo=s.hasVideo),this._demuxer.timestampBase=s.segments[this._currentSegmentIndex].timestampBase,this._demuxer.onError=this._onDemuxException.bind(this),this._demuxer.onMediaInfo=this._onMediaInfo.bind(this),this._remuxer.bindDataSource(this._demuxer.bindDataSource(this._ioctl)),this._remuxer.onInitSegment=this._onRemuxerInitSegmentArrival.bind(this),this._remuxer.onMediaSegment=this._onRemuxerMediaSegmentArrival.bind(this),r=this._demuxer.parseChunks(e,t)}else i=null,l.default.e(this.TAG,"Non-FLV, Unsupported media type!"),Promise.resolve().then(function(){n._internalAbort()}),this._emitter.emit(k.default.DEMUX_ERROR,y.default.FORMAT_UNSUPPORTED,"Non-FLV, Unsupported media type"),r=0;return r}},{key:"_onMediaInfo",value:function(e){var t=this;null==this._mediaInfo&&(this._mediaInfo=Object.assign({},e),this._mediaInfo.keyframesIndex=null,this._mediaInfo.segments=[],this._mediaInfo.segmentCount=this._mediaDataSource.segments.length,Object.setPrototypeOf(this._mediaInfo,c.default.prototype));var n=Object.assign({},e);Object.setPrototypeOf(n,c.default.prototype),this._mediaInfo.segments[this._currentSegmentIndex]=n,this._reportSegmentMediaInfo(this._currentSegmentIndex),null!=this._pendingSeekTime&&Promise.resolve().then(function(){var e=t._pendingSeekTime;t._pendingSeekTime=null,t.seek(e)})}},{key:"_onIOSeeked",value:function(){this._remuxer.insertDiscontinuity()}},{key:"_onIOComplete",value:function(e){var t=e,n=t+1;n0&&n[0].originalDts===i&&(i=n[0].pts),this._emitter.emit(k.default.RECOMMEND_SEEKPOINT,i)}}},{key:"_enableStatisticsReporter",value:function(){null==this._statisticsReporter&&(this._statisticsReporter=self.setInterval(this._reportStatisticsInfo.bind(this),this._config.statisticsInfoReportInterval))}},{key:"_disableStatisticsReporter",value:function(){this._statisticsReporter&&(self.clearInterval(this._statisticsReporter),this._statisticsReporter=null)}},{key:"_reportSegmentMediaInfo",value:function(e){var t=this._mediaInfo.segments[e],n=Object.assign({},t);n.duration=this._mediaInfo.duration,n.segmentCount=this._mediaInfo.segmentCount,delete n.segments,delete n.keyframesIndex,this._emitter.emit(k.default.MEDIA_INFO,n)}},{key:"_reportStatisticsInfo",value:function(){var e={};e.url=this._ioctl.currentURL,e.hasRedirect=this._ioctl.hasRedirect,e.hasRedirect&&(e.redirectedURL=this._ioctl.currentRedirectedURL),e.speed=this._ioctl.currentSpeed,e.loaderType=this._ioctl.loaderType,e.currentSegmentIndex=this._currentSegmentIndex,e.totalSegmentCount=this._mediaDataSource.segments.length,this._emitter.emit(k.default.STATISTICS_INFO,e)}}]),e}());n.default=L},{"../demux/demux-errors.js":16,"../demux/flv-demuxer.js":18,"../io/io-controller.js":23,"../io/loader.js":24,"../remux/mp4-remuxer.js":38,"../utils/browser.js":39,"../utils/logger.js":41,"./media-info.js":7,"./transmuxing-events.js":13,events:2}],13:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var i={IO_ERROR:"io_error",DEMUX_ERROR:"demux_error",INIT_SEGMENT:"init_segment",MEDIA_SEGMENT:"media_segment",LOADING_COMPLETE:"loading_complete",RECOVERED_EARLY_EOF:"recovered_early_eof",MEDIA_INFO:"media_info",STATISTICS_INFO:"statistics_info",RECOMMEND_SEEKPOINT:"recommend_seekpoint"};n.default=i},{}],14:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(n,"__esModule",{value:!0});var r=e("../utils/logger.js"),s=(i(r),e("../utils/logging-control.js")),a=i(s),o=e("../utils/polyfill.js"),u=i(o),l=e("./transmuxing-controller.js"),d=i(l),h=e("./transmuxing-events.js"),f=i(h),c=function(e){function t(t,n){var i={msg:f.default.INIT_SEGMENT,data:{type:t,data:n}};e.postMessage(i,[n.data])}function n(t,n){var i={msg:f.default.MEDIA_SEGMENT,data:{type:t,data:n}};e.postMessage(i,[n.data])}function i(){var t={msg:f.default.LOADING_COMPLETE};e.postMessage(t)}function r(){var t={msg:f.default.RECOVERED_EARLY_EOF};e.postMessage(t)}function s(t){var n={msg:f.default.MEDIA_INFO,data:t};e.postMessage(n)}function o(t){var n={msg:f.default.STATISTICS_INFO,data:t};e.postMessage(n)}function l(t,n){e.postMessage({msg:f.default.IO_ERROR,data:{type:t,info:n}})}function h(t,n){e.postMessage({msg:f.default.DEMUX_ERROR,data:{type:t,info:n}})}function c(t){e.postMessage({msg:f.default.RECOMMEND_SEEKPOINT,data:t})}function _(t,n){e.postMessage({msg:"logcat_callback",data:{type:t,logcat:n}})}var m=null,p=_.bind(this);u.default.install(),e.addEventListener("message",function(u){switch(u.data.cmd){case"init":m=new d.default(u.data.param[0],u.data.param[1]),m.on(f.default.IO_ERROR,l.bind(this)),m.on(f.default.DEMUX_ERROR,h.bind(this)),m.on(f.default.INIT_SEGMENT,t.bind(this)),m.on(f.default.MEDIA_SEGMENT,n.bind(this)),m.on(f.default.LOADING_COMPLETE,i.bind(this)),m.on(f.default.RECOVERED_EARLY_EOF,r.bind(this)),m.on(f.default.MEDIA_INFO,s.bind(this)),m.on(f.default.STATISTICS_INFO,o.bind(this)),m.on(f.default.RECOMMEND_SEEKPOINT,c.bind(this));break;case"destroy":m&&(m.destroy(),m=null),e.postMessage({msg:"destroyed"});break;case"start":m.start();break;case"stop":m.stop();break;case"seek":m.seek(u.data.param);break;case"pause":m.pause();break;case"resume":m.resume();break;case"logging_config":var _=u.data.param;a.default.applyConfig(_),!0===_.enableCallback?a.default.addLogListener(p):a.default.removeLogListener(p)}})};n.default=c},{"../utils/logger.js":41,"../utils/logging-control.js":42,"../utils/polyfill.js":43,"./transmuxing-controller.js":12,"./transmuxing-events.js":13}],15:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var s=function(){function e(e,t){for(var n=0;n0?(0,l.default)(new Uint8Array(e,t+2,r)):"",{data:s,size:2+r}}},{key:"parseLongString",value:function(e,t,n){if(n<4)throw new d.IllegalStateException("Data not enough when parse LongString");var i=new DataView(e,t,n),r=i.getUint32(0,!h),s=void 0;return s=r>0?(0,l.default)(new Uint8Array(e,t+4,r)):"",{data:s,size:4+r}}},{key:"parseDate",value:function(e,t,n){if(n<10)throw new d.IllegalStateException("Data size invalid when parse Date");var i=new DataView(e,t,n),r=i.getFloat64(0,!h);return r+=60*i.getInt16(8,!h)*1e3,{data:new Date(r),size:10}}},{key:"parseValue",value:function(t,n,i){if(i<1)throw new d.IllegalStateException("Data not enough when parse Value");var r=new DataView(t,n,i),s=1,a=r.getUint8(0),u=void 0,l=!1;try{switch(a){case 0:u=r.getFloat64(1,!h),s+=8;break;case 1:u=!!r.getUint8(1),s+=1;break;case 2:var f=e.parseString(t,n+1,i-1);u=f.data,s+=f.size;break;case 3:u={};var c=0;for(9==(16777215&r.getUint32(i-4,!h))&&(c=3);s32)throw new s.InvalidArgumentException("ExpGolomb: readBits() bits exceeded max 32bits!");if(e<=this._current_word_bits_left){var t=this._current_word>>>32-e;return this._current_word<<=e,this._current_word_bits_left-=e,t}var n=this._current_word_bits_left?this._current_word:0;n>>>=32-this._current_word_bits_left;var i=e-this._current_word_bits_left;this._fillCurrentWord();var r=Math.min(i,this._current_word_bits_left),a=this._current_word>>>32-r;return this._current_word<<=r,this._current_word_bits_left-=r,n=n<>>e))return this._current_word<<=e,this._current_word_bits_left-=e,e;return this._fillCurrentWord(),e+this._skipLeadingZero()}},{key:"readUEG",value:function(){var e=this._skipLeadingZero();return this.readBits(e+1)-1}},{key:"readSEG",value:function(){var e=this.readUEG();return 1&e?e+1>>>1:-1*(e>>>1)}}]),e}();n.default=a},{"../utils/exception.js":40}],18:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){return e[t]<<24|e[t+1]<<16|e[t+2]<<8|e[t+3]}Object.defineProperty(n,"__esModule",{value:!0});var a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o=function(){function e(e,t){for(var n=0;n13))return 0;i=e.probe(t).dataOffset}if(this._firstParse){this._firstParse=!1,n+i!==this._dataOffset&&l.default.w(this.TAG,"First time parsing but chunk byteStart invalid!");0!==new DataView(t,i).getUint32(0,!r)&&l.default.w(this.TAG,"PrevTagSize0 !== 0 !!!"),i+=4}for(;it.byteLength)break;var a=s.getUint8(0),o=16777215&s.getUint32(0,!r);if(i+11+o+4>t.byteLength)break;if(8===a||9===a||18===a){var u=s.getUint8(4),d=s.getUint8(5),h=s.getUint8(6),f=s.getUint8(7),c=h|d<<8|u<<16|f<<24;0!==(16777215&s.getUint32(7,!r))&&l.default.w(this.TAG,"Meet tag which has StreamID != 0!");var _=i+11;switch(a){case 8:this._parseAudioData(t,_,o,c);break;case 9:this._parseVideoData(t,_,o,c,n+i);break;case 18:this._parseScriptData(t,_,o)}var m=s.getUint32(11+o,!r);m!==11+o&&l.default.w(this.TAG,"Invalid PrevTagSize "+m),i+=11+o+4}else l.default.w(this.TAG,"Unsupported tag type "+a+", skipped"),i+=11+o+4}return this._isInitialMetadataDispatched()&&this._dispatch&&(this._audioTrack.length||this._videoTrack.length)&&this._onDataAvailable(this._audioTrack,this._videoTrack),i}},{key:"_parseScriptData",value:function(e,t,n){var i=h.default.parseScriptData(e,t,n);if(i.hasOwnProperty("onMetaData")){if(null==i.onMetaData||"object"!==a(i.onMetaData))return void l.default.w(this.TAG,"Invalid onMetaData structure!");this._metadata&&l.default.w(this.TAG,"Found another onMetaData tag!"),this._metadata=i;var r=this._metadata.onMetaData;if("boolean"==typeof r.hasAudio&&!1===this._hasAudioFlagOverrided&&(this._hasAudio=r.hasAudio,this._mediaInfo.hasAudio=this._hasAudio),"boolean"==typeof r.hasVideo&&!1===this._hasVideoFlagOverrided&&(this._hasVideo=r.hasVideo,this._mediaInfo.hasVideo=this._hasVideo),"number"==typeof r.audiodatarate&&(this._mediaInfo.audioDataRate=r.audiodatarate),"number"==typeof r.videodatarate&&(this._mediaInfo.videoDataRate=r.videodatarate),"number"==typeof r.width&&(this._mediaInfo.width=r.width),"number"==typeof r.height&&(this._mediaInfo.height=r.height),"number"==typeof r.duration){if(!this._durationOverrided){var s=Math.floor(r.duration*this._timescale);this._duration=s,this._mediaInfo.duration=s}}else this._mediaInfo.duration=0;if("number"==typeof r.framerate){var o=Math.floor(1e3*r.framerate);if(o>0){var u=o/1e3;this._referenceFrameRate.fixed=!0,this._referenceFrameRate.fps=u,this._referenceFrameRate.fps_num=o,this._referenceFrameRate.fps_den=1e3,this._mediaInfo.fps=u}}if("object"===a(r.keyframes)){this._mediaInfo.hasKeyframesIndex=!0;var d=r.keyframes;this._mediaInfo.keyframesIndex=this._parseKeyframesIndex(d),r.keyframes=null}else this._mediaInfo.hasKeyframesIndex=!1;this._dispatch=!1,this._mediaInfo.metadata=r,l.default.v(this.TAG,"Parsed onMetaData"),this._mediaInfo.isComplete()&&this._onMediaInfo(this._mediaInfo)}}},{key:"_parseKeyframesIndex",value:function(e){for(var t=[],n=[],i=1;i>>4;if(2!==a&&10!==a)return void this._onError(m.default.CODEC_UNSUPPORTED,"Flv: Unsupported audio codec idx: "+a);var o=0,u=(12&s)>>>2;if(!(u>=0&&u<=4))return void this._onError(m.default.FORMAT_ERROR,"Flv: Invalid audio sample rate idx: "+u);o=this._flvSoundRateTable[u];var d=1&s,h=this._audioMetadata,f=this._audioTrack;if(h||(!1===this._hasAudio&&!1===this._hasAudioFlagOverrided&&(this._hasAudio=!0,this._mediaInfo.hasAudio=!0),h=this._audioMetadata={},h.type="audio",h.id=f.id,h.timescale=this._timescale,h.duration=this._duration,h.audioSampleRate=o,h.channelCount=0===d?1:2),10===a){var c=this._parseAACAudioData(e,t+1,n-1);if(void 0==c)return;if(0===c.packetType){h.config&&l.default.w(this.TAG,"Found another AudioSpecificConfig!");var _=c.data;h.audioSampleRate=_.samplingRate,h.channelCount=_.channelCount,h.codec=_.codec,h.originalCodec=_.originalCodec,h.config=_.config,h.refSampleDuration=1024/h.audioSampleRate*h.timescale,l.default.v(this.TAG,"Parsed AudioSpecificConfig"),this._isInitialMetadataDispatched()?this._dispatch&&(this._audioTrack.length||this._videoTrack.length)&&this._onDataAvailable(this._audioTrack,this._videoTrack):this._audioInitialMetadataDispatched=!0,this._dispatch=!1,this._onTrackMetadata("audio",h);var p=this._mediaInfo;p.audioCodec=h.originalCodec,p.audioSampleRate=h.audioSampleRate,p.audioChannelCount=h.channelCount,p.hasVideo?null!=p.videoCodec&&(p.mimeType='video/x-flv; codecs="'+p.videoCodec+","+p.audioCodec+'"'):p.mimeType='video/x-flv; codecs="'+p.audioCodec+'"',p.isComplete()&&this._onMediaInfo(p)}else if(1===c.packetType){var v=this._timestampBase+i,g={unit:c.data,length:c.data.byteLength,dts:v,pts:v};f.samples.push(g),f.length+=c.data.length}else l.default.e(this.TAG,"Flv: Unsupported AAC data type "+c.packetType)}else if(2===a){if(!h.codec){var y=this._parseMP3AudioData(e,t+1,n-1,!0);if(void 0==y)return;h.audioSampleRate=y.samplingRate,h.channelCount=y.channelCount,h.codec=y.codec,h.originalCodec=y.originalCodec,h.refSampleDuration=1152/h.audioSampleRate*h.timescale,l.default.v(this.TAG,"Parsed MPEG Audio Frame Header"),this._audioInitialMetadataDispatched=!0,this._onTrackMetadata("audio",h);var E=this._mediaInfo;E.audioCodec=h.codec,E.audioSampleRate=h.audioSampleRate,E.audioChannelCount=h.channelCount,E.audioDataRate=y.bitRate,E.hasVideo?null!=E.videoCodec&&(E.mimeType='video/x-flv; codecs="'+E.videoCodec+","+E.audioCodec+'"'):E.mimeType='video/x-flv; codecs="'+E.audioCodec+'"',E.isComplete()&&this._onMediaInfo(E)}var b=this._parseMP3AudioData(e,t+1,n-1,!1);if(void 0==b)return +;var S=this._timestampBase+i,k={unit:b,length:b.byteLength,dts:S,pts:S};f.samples.push(k),f.length+=b.length}}}},{key:"_parseAACAudioData",value:function(e,t,n){if(n<=1)return void l.default.w(this.TAG,"Flv: Invalid AAC packet, missing AACPacketType or/and Data!");var i={},r=new Uint8Array(e,t,n);return i.packetType=r[0],0===r[0]?i.data=this._parseAACAudioSpecificConfig(e,t+1,n-1):i.data=r.subarray(1),i}},{key:"_parseAACAudioSpecificConfig",value:function(e,t,n){var i=new Uint8Array(e,t,n),r=null,s=0,a=0,o=0,u=null;if(s=a=i[0]>>>3,(o=(7&i[0])<<1|i[1]>>>7)<0||o>=this._mpegSamplingRates.length)return void this._onError(m.default.FORMAT_ERROR,"Flv: AAC invalid sampling frequency index!");var l=this._mpegSamplingRates[o],d=(120&i[1])>>>3;if(d<0||d>=8)return void this._onError(m.default.FORMAT_ERROR,"Flv: AAC invalid channel configuration");5===s&&(u=(7&i[1])<<1|i[2]>>>7,i[2]);var h=self.navigator.userAgent.toLowerCase();return-1!==h.indexOf("firefox")?o>=6?(s=5,r=new Array(4),u=o-3):(s=2,r=new Array(2),u=o):-1!==h.indexOf("android")?(s=2,r=new Array(2),u=o):(s=5,u=o,r=new Array(4),o>=6?u=o-3:1===d&&(s=2,r=new Array(2),u=o)),r[0]=s<<3,r[0]|=(15&o)>>>1,r[1]=(15&o)<<7,r[1]|=(15&d)<<3,5===s&&(r[1]|=(15&u)>>>1,r[2]=(1&u)<<7,r[2]|=8,r[3]=0),{config:r,samplingRate:l,channelCount:d,codec:"mp4a.40."+s,originalCodec:"mp4a.40."+a}}},{key:"_parseMP3AudioData",value:function(e,t,n,i){if(n<4)return void l.default.w(this.TAG,"Flv: Invalid MP3 packet, header missing!");var r=(this._littleEndian,new Uint8Array(e,t,n)),s=null;if(i){if(255!==r[0])return;var a=r[1]>>>3&3,o=(6&r[1])>>1,u=(240&r[2])>>>4,d=(12&r[2])>>>2,h=r[3]>>>6&3,f=3!==h?2:1,c=0,_=0;switch(a){case 0:c=this._mpegAudioV25SampleRateTable[d];break;case 2:c=this._mpegAudioV20SampleRateTable[d];break;case 3:c=this._mpegAudioV10SampleRateTable[d]}switch(o){case 1:34,u>>4,o=15&s;if(7!==o)return void this._onError(m.default.CODEC_UNSUPPORTED,"Flv: Unsupported codec in video frame: "+o);this._parseAVCVideoPacket(e,t+1,n-1,i,r,a)}}},{key:"_parseAVCVideoPacket",value:function(e,t,n,i,r,s){if(n<4)return void l.default.w(this.TAG,"Flv: Invalid AVC packet, missing AVCPacketType or/and CompositionTime");var a=this._littleEndian,o=new DataView(e,t,n),u=o.getUint8(0),d=16777215&o.getUint32(0,!a),h=d<<8>>8;if(0===u)this._parseAVCDecoderConfigurationRecord(e,t+4,n-4);else if(1===u)this._parseAVCVideoData(e,t+4,n-4,i,r,s,h);else if(2!==u)return void this._onError(m.default.FORMAT_ERROR,"Flv: Invalid video packet type "+u)}},{key:"_parseAVCDecoderConfigurationRecord",value:function(e,t,n){if(n<7)return void l.default.w(this.TAG,"Flv: Invalid AVCDecoderConfigurationRecord, lack of data!");var i=this._videoMetadata,r=this._videoTrack,s=this._littleEndian,a=new DataView(e,t,n);i?void 0!==i.avcc&&l.default.w(this.TAG,"Found another AVCDecoderConfigurationRecord!"):(!1===this._hasVideo&&!1===this._hasVideoFlagOverrided&&(this._hasVideo=!0,this._mediaInfo.hasVideo=!0),i=this._videoMetadata={},i.type="video",i.id=r.id,i.timescale=this._timescale,i.duration=this._duration);var o=a.getUint8(0),u=a.getUint8(1);a.getUint8(2),a.getUint8(3);if(1!==o||0===u)return void this._onError(m.default.FORMAT_ERROR,"Flv: Invalid AVCDecoderConfigurationRecord");if(this._naluLengthSize=1+(3&a.getUint8(4)),3!==this._naluLengthSize&&4!==this._naluLengthSize)return void this._onError(m.default.FORMAT_ERROR,"Flv: Strange NaluLengthSizeMinusOne: "+(this._naluLengthSize-1));var d=31&a.getUint8(5);if(0===d)return void this._onError(m.default.FORMAT_ERROR,"Flv: Invalid AVCDecoderConfigurationRecord: No SPS");d>1&&l.default.w(this.TAG,"Flv: Strange AVCDecoderConfigurationRecord: SPS Count = "+d);for(var h=6,f=0;f1&&l.default.w(this.TAG,"Flv: Strange AVCDecoderConfigurationRecord: PPS Count = "+w),h++;for(var R=0;R=n){l.default.w(this.TAG,"Malformed Nalu near timestamp "+_+", offset = "+f+", dataSize = "+n);break}var p=u.getUint32(f,!o);if(3===c&&(p>>>=8),p>n-c)return void l.default.w(this.TAG,"Malformed Nalus near timestamp "+_+", NaluSize > DataSize!");var v=31&u.getUint8(f+c);5===v&&(m=!0);var g=new Uint8Array(e,t+f,c+p),y={type:v,data:g};d.push(y),h+=g.byteLength,f+=c+p}if(d.length){var E=this._videoTrack,b={units:d,length:h,isKeyframe:m,dts:_,cts:a,pts:_+a};m&&(b.fileposition=r),E.samples.push(b),E.length+=h}}},{key:"onTrackMetadata",get:function(){return this._onTrackMetadata},set:function(e){this._onTrackMetadata=e}},{key:"onMediaInfo",get:function(){return this._onMediaInfo},set:function(e){this._onMediaInfo=e}},{key:"onError",get:function(){return this._onError},set:function(e){this._onError=e}},{key:"onDataAvailable",get:function(){return this._onDataAvailable},set:function(e){this._onDataAvailable=e}},{key:"timestampBase",get:function(){return this._timestampBase},set:function(e){this._timestampBase=e}},{key:"overridedDuration",get:function(){return this._duration},set:function(e){this._durationOverrided=!0,this._duration=e,this._mediaInfo.duration=e}},{key:"overridedHasAudio",set:function(e){this._hasAudioFlagOverrided=!0,this._hasAudio=e,this._mediaInfo.hasAudio=e}},{key:"overridedHasVideo",set:function(e){this._hasVideoFlagOverrided=!0,this._hasVideo=e,this._mediaInfo.hasVideo=e}}],[{key:"probe",value:function(e){var t=new Uint8Array(e),n={match:!1};if(70!==t[0]||76!==t[1]||86!==t[2]||1!==t[3])return n;var i=(4&t[4])>>>2!=0,r=0!=(1&t[4]),a=s(t,5);return a<9?n:{match:!0,consumed:a,dataOffset:a,hasAudioTrack:i,hasVideoTrack:r}}}]),e}();n.default=y},{"../core/media-info.js":7,"../utils/exception.js":40,"../utils/logger.js":41,"./amf-parser.js":15,"./demux-errors.js":16,"./sps-parser.js":19}],19:[function(e,t,n){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function e(e,t){for(var n=0;n=2&&3===t[s]&&0===t[s-1]&&0===t[s-2]||(i[r]=t[s],r++);return new Uint8Array(i.buffer,0,r)}},{key:"parseSPS",value:function(t){var n=e._ebsp2rbsp(t),i=new a.default(n);i.readByte();var r=i.readByte();i.readByte();var s=i.readByte();i.readUEG();var o=e.getProfileString(r),u=e.getLevelString(s),l=1,d=420,h=[0,420,422,444],f=8;if((100===r||110===r||122===r||244===r||44===r||83===r||86===r||118===r||128===r||138===r||144===r)&&(l=i.readUEG(),3===l&&i.readBits(1),l<=3&&(d=h[l]),f=i.readUEG()+8,i.readUEG(),i.readBits(1),i.readBool()))for(var c=3!==l?8:12,_=0;_0&&x<16?(R=M[x-1],A=D[x-1]):255===x&&(R=i.readByte()<<8|i.readByte(),A=i.readByte()<<8|i.readByte())}if(i.readBool()&&i.readBool(),i.readBool()&&(i.readBits(4),i.readBool()&&i.readBits(24)),i.readBool()&&(i.readUEG(),i.readUEG()),i.readBool()){var B=i.readBits(32),j=i.readBits(32);T=i.readBool(),C=j,I=2*B,O=C/I}}var P=1;1===R&&1===A||(P=R/A);var U=0,N=0;if(0===l)U=1,N=2-b;else{var F=3===l?1:2,G=1===l?2:1;U=F,N=G*(2-b)}var V=16*(y+1),z=16*(E+1)*(2-b);V-=(S+k)*U,z-=(L+w)*N;var H=Math.ceil(V*P);return i.destroy(),i=null,{profile_string:o,level_string:u,bit_depth:f,ref_frames:g,chroma_format:d,chroma_format_string:e.getChromaFormatString(d),frame_rate:{fixed:T,fps:O,fps_den:I,fps_num:C},sar_ratio:{width:R,height:A},codec_size:{width:V,height:z},present_size:{width:H,height:z}}}},{key:"_skipScalingList",value:function(e,t){for(var n=8,i=8,r=0,s=0;s=15048,t=!f.default.msedge||e;return self.fetch&&self.ReadableStream&&t}catch(e){return!1}}}]),l(t,[{key:"destroy",value:function(){this.isWorking()&&this.abort(),u(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"destroy",this).call(this)}},{key:"open",value:function(e,t){var n=this;this._dataSource=e,this._range=t;var i=e.url;this._config.reuseRedirectedURL&&void 0!=e.redirectedURL&&(i=e.redirectedURL);var r=this._seekHandler.getConfig(i,t),s=new self.Headers;if("object"===o(r.headers)){var a=r.headers;for(var u in a)a.hasOwnProperty(u)&&s.append(u,a[u])}var l={method:"GET",headers:s,mode:"cors",cache:"default",referrerPolicy:"no-referrer-when-downgrade"};!1===e.cors&&(l.mode="same-origin"),e.withCredentials&&(l.credentials="include"),e.referrerPolicy&&(l.referrerPolicy=e.referrerPolicy),this._status=c.LoaderStatus.kConnecting,self.fetch(r.url,l).then(function(e){if(n._requestAbort)return n._requestAbort=!1,void(n._status=c.LoaderStatus.kIdle);if(e.ok&&e.status>=200&&e.status<=299){if(e.url!==r.url&&n._onURLRedirect){var t=n._seekHandler.removeURLParameters(e.url);n._onURLRedirect(t)}var i=e.headers.get("Content-Length");return null!=i&&(n._contentLength=parseInt(i),0!==n._contentLength&&n._onContentLengthKnown&&n._onContentLengthKnown(n._contentLength)),n._pump.call(n,e.body.getReader())}if(n._status=c.LoaderStatus.kError,!n._onError)throw new _.RuntimeException("FetchStreamLoader: Http code invalid, "+e.status+" "+e.statusText);n._onError(c.LoaderErrors.HTTP_STATUS_CODE_INVALID,{code:e.status,msg:e.statusText})}).catch(function(e){if(n._status=c.LoaderStatus.kError,!n._onError)throw e;n._onError(c.LoaderErrors.EXCEPTION,{code:-1,msg:e.message})})}},{key:"abort",value:function(){this._requestAbort=!0}},{key:"_pump",value:function(e){var t=this;return e.read().then(function(n){if(n.done)if(null!==t._contentLength&&t._receivedLength0&&(this._stashInitialSize=n.stashInitialSize),this._stashUsed=0,this._stashSize=this._stashInitialSize,this._bufferSize=3145728,this._stashBuffer=new ArrayBuffer(this._bufferSize),this._stashByteStart=0,this._enableStash=!0,!1===n.enableStashBuffer&&(this._enableStash=!1),this._loader=null,this._loaderClass=null,this._seekHandler=null,this._dataSource=t,this._isWebSocketURL=/wss?:\/\/(.+?)/.test(t.url),this._refTotalLength=t.filesize?t.filesize:null,this._totalLength=this._refTotalLength,this._fullRequestFlag=!1,this._currentRange=null,this._redirectedURL=null,this._speedNormalized=0,this._speedSampler=new l.default,this._speedNormalizeList=[64,128,256,384,512,768,1024,1536,2048,3072,4096],this._isEarlyEofReconnecting=!1,this._paused=!1,this._resumeFrom=0,this._onDataArrival=null,this._onSeeked=null,this._onError=null,this._onComplete=null,this._onRedirect=null,this._onRecoveredEarlyEof=null,this._selectSeekHandler(),this._selectLoader(),this._createLoader()}return s(e,[{key:"destroy",value:function(){this._loader.isWorking()&&this._loader.abort(),this._loader.destroy(),this._loader=null,this._loaderClass=null,this._dataSource=null,this._stashBuffer=null,this._stashUsed=this._stashSize=this._bufferSize=this._stashByteStart=0,this._currentRange=null,this._speedSampler=null,this._isEarlyEofReconnecting=!1,this._onDataArrival=null,this._onSeeked=null,this._onError=null,this._onComplete=null,this._onRedirect=null,this._onRecoveredEarlyEof=null,this._extraData=null}},{key:"isWorking",value:function(){return this._loader&&this._loader.isWorking()&&!this._paused}},{key:"isPaused",value:function(){return this._paused}},{key:"_selectSeekHandler",value:function(){var e=this._config;if("range"===e.seekType)this._seekHandler=new b.default(this._config.rangeLoadZeroStart);else if("param"===e.seekType){var t=e.seekParamStart||"bstart",n=e.seekParamEnd||"bend";this._seekHandler=new k.default(t,n)}else{if("custom"!==e.seekType)throw new L.InvalidArgumentException("Invalid seekType in config: "+e.seekType);if("function"!=typeof e.customSeekHandler)throw new L.InvalidArgumentException("Custom seekType specified in config but invalid customSeekHandler!");this._seekHandler=new e.customSeekHandler}}},{key:"_selectLoader",value:function(){if(this._isWebSocketURL)this._loaderClass=y.default;else if(f.default.isSupported())this._loaderClass=f.default;else if(_.default.isSupported())this._loaderClass=_.default;else{if(!v.default.isSupported())throw new L.RuntimeException("Your browser doesn't support xhr with arraybuffer responseType!");this._loaderClass=v.default}}},{key:"_createLoader",value:function(){this._loader=new this._loaderClass(this._seekHandler,this._config),!1===this._loader.needStashBuffer&&(this._enableStash=!1),this._loader.onContentLengthKnown=this._onContentLengthKnown.bind(this),this._loader.onURLRedirect=this._onURLRedirect.bind(this),this._loader.onDataArrival=this._onLoaderChunkArrival.bind(this),this._loader.onComplete=this._onLoaderComplete.bind(this),this._loader.onError=this._onLoaderError.bind(this)}},{key:"open",value:function(e){this._currentRange={from:0,to:-1},e&&(this._currentRange.from=e),this._speedSampler.reset(),e||(this._fullRequestFlag=!0),this._loader.open(this._dataSource,Object.assign({},this._currentRange))}},{key:"abort",value:function(){this._loader.abort(),this._paused&&(this._paused=!1,this._resumeFrom=0)}},{key:"pause",value:function(){this.isWorking()&&(this._loader.abort(),0!==this._stashUsed?(this._resumeFrom=this._stashByteStart,this._currentRange.to=this._stashByteStart-1):this._resumeFrom=this._currentRange.to+1,this._stashUsed=0,this._stashByteStart=0,this._paused=!0)}},{key:"resume",value:function(){if(this._paused){this._paused=!1;var e=this._resumeFrom;this._resumeFrom=0,this._internalSeek(e,!0)}}},{key:"seek",value:function(e){this._paused=!1,this._stashUsed=0,this._stashByteStart=0,this._internalSeek(e,!0)}},{key:"_internalSeek",value:function(e,t){this._loader.isWorking()&&this._loader.abort(),this._flushStashBuffer(t),this._loader.destroy(),this._loader=null;var n={from:e,to:-1};this._currentRange={from:n.from,to:-1},this._speedSampler.reset(),this._stashSize=this._stashInitialSize,this._createLoader(),this._loader.open(this._dataSource,n),this._onSeeked&&this._onSeeked()}},{key:"updateUrl",value:function(e){if(!e||"string"!=typeof e||0===e.length)throw new L.InvalidArgumentException("Url must be a non-empty string!");this._dataSource.url=e}},{key:"_expandBuffer",value:function(e){for(var t=this._stashSize;t+10485760){var i=new Uint8Array(this._stashBuffer,0,this._stashUsed);new Uint8Array(n,0,t).set(i,0)}this._stashBuffer=n,this._bufferSize=t}}},{key:"_normalizeSpeed",value:function(e){var t=this._speedNormalizeList,n=t.length-1,i=0,r=0,s=n;if(e=t[i]&&e=512&&e<=1024?Math.floor(1.5*e):2*e)>8192&&(t=8192);var n=1024*t+1048576;this._bufferSize0){var o=this._stashBuffer.slice(0,this._stashUsed),u=this._dispatchChunks(o,this._stashByteStart);if(u0){var l=new Uint8Array(o,u);a.set(l,0),this._stashUsed=l.byteLength,this._stashByteStart+=u}}else this._stashUsed=0,this._stashByteStart+=u;this._stashUsed+e.byteLength>this._bufferSize&&(this._expandBuffer(this._stashUsed+e.byteLength),a=new Uint8Array(this._stashBuffer,0,this._bufferSize)),a.set(new Uint8Array(e),this._stashUsed),this._stashUsed+=e.byteLength}else{var d=this._dispatchChunks(e,t);if(dthis._bufferSize&&(this._expandBuffer(h),a=new Uint8Array(this._stashBuffer,0,this._bufferSize)),a.set(new Uint8Array(e,d),0),this._stashUsed+=h,this._stashByteStart=t+d}}}else if(0===this._stashUsed){var f=this._dispatchChunks(e,t);if(fthis._bufferSize&&this._expandBuffer(c);var _=new Uint8Array(this._stashBuffer,0,this._bufferSize);_.set(new Uint8Array(e,f),0),this._stashUsed+=c,this._stashByteStart=t+f}}else{this._stashUsed+e.byteLength>this._bufferSize&&this._expandBuffer(this._stashUsed+e.byteLength);var m=new Uint8Array(this._stashBuffer,0,this._bufferSize);m.set(new Uint8Array(e),this._stashUsed),this._stashUsed+=e.byteLength;var p=this._dispatchChunks(this._stashBuffer.slice(0,this._stashUsed),this._stashByteStart);if(p0){var v=new Uint8Array(this._stashBuffer,p);m.set(v,0)}this._stashUsed-=p,this._stashByteStart+=p}}}},{key:"_flushStashBuffer",value:function(e){if(this._stashUsed>0){var t=this._stashBuffer.slice(0,this._stashUsed),n=this._dispatchChunks(t,this._stashByteStart),i=t.byteLength-n;if(n0){var r=new Uint8Array(this._stashBuffer,0,this._bufferSize),s=new Uint8Array(t,n);r.set(s,0),this._stashUsed=s.byteLength,this._stashByteStart+=n}return 0}o.default.w(this.TAG,i+" bytes unconsumed data remain when flush buffer, dropped")}return this._stashUsed=0,this._stashByteStart=0,i}return 0}},{key:"_onLoaderComplete",value:function(e,t){this._flushStashBuffer(!0),this._onComplete&&this._onComplete(this._extraData)}},{key:"_onLoaderError",value:function(e,t){switch(o.default.e(this.TAG,"Loader error, code = "+t.code+", msg = "+t.msg),this._flushStashBuffer(!1),this._isEarlyEofReconnecting&&(this._isEarlyEofReconnecting=!1,e=d.LoaderErrors.UNRECOVERABLE_EARLY_EOF),e){case d.LoaderErrors.EARLY_EOF:if(!this._config.isLive&&this._totalLength){var n=this._currentRange.to+1;return void(n0)for(var s=n.split("&"),a=0;a0;o[0]!==this._startName&&o[0]!==this._endName&&(u&&(r+="&"),r+=s[a])}return 0===r.length?t:t+"?"+r}}]),e}();n.default=s},{}],26:[function(e,t,n){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function e(e,t){for(var n=0;n=500?this.currentKBps:0}},{key:"averageKBps",get:function(){var e=(this._now()-this._firstCheckpoint)/1e3;return this._totalBytes/e/1024}}]),e}();n.default=s},{}],28:[function(e,t,n){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(n,"__esModule",{value:!0});var a=function e(t,n,i){null===t&&(t=Function.prototype);var r=Object.getOwnPropertyDescriptor(t,n);if(void 0===r){var s=Object.getPrototypeOf(t);return null===s?void 0:e(s,n,i)}if("value"in r)return r.value;var a=r.get;if(void 0!==a)return a.call(i)},o=function(){function e(e,t){for(var n=0;n299)){if(this._status=h.LoaderStatus.kError,!this._onError)throw new f.RuntimeException("MozChunkedLoader: Http code invalid, "+t.status+" "+t.statusText);this._onError(h.LoaderErrors.HTTP_STATUS_CODE_INVALID,{code:t.status,msg:t.statusText})}else this._status=h.LoaderStatus.kBuffering}}},{key:"_onProgress",value:function(e){if(this._status!==h.LoaderStatus.kError){null===this._contentLength&&null!==e.total&&0!==e.total&&(this._contentLength=e.total,this._onContentLengthKnown&&this._onContentLengthKnown(this._contentLength));var t=e.target.response,n=this._range.from+this._receivedLength;this._receivedLength+=t.byteLength,this._onDataArrival&&this._onDataArrival(t,n,this._receivedLength)}}},{key:"_onLoadEnd",value:function(e){if(!0===this._requestAbort)return void(this._requestAbort=!1);this._status!==h.LoaderStatus.kError&&(this._status=h.LoaderStatus.kComplete,this._onComplete&&this._onComplete(this._range.from,this._range.from+this._receivedLength-1))}},{key:"_onXhrError",value:function(e){this._status=h.LoaderStatus.kError;var t=0,n=null;if(this._contentLength&&e.loaded=200&&t.status<=299){if(this._status=h.LoaderStatus.kBuffering,void 0!=t.responseURL){var n=this._seekHandler.removeURLParameters(t.responseURL);t.responseURL!==this._currentRequestURL&&n!==this._currentRedirectedURL&&(this._currentRedirectedURL=n,this._onURLRedirect&&this._onURLRedirect(n))}var i=t.getResponseHeader("Content-Length");if(null!=i&&null==this._contentLength){var r=parseInt(i);r>0&&(this._contentLength=r,this._onContentLengthKnown&&this._onContentLengthKnown(this._contentLength))}}else{if(this._status=h.LoaderStatus.kError,!this._onError)throw new f.RuntimeException("MSStreamLoader: Http code invalid, "+t.status+" "+t.statusText);this._onError(h.LoaderErrors.HTTP_STATUS_CODE_INVALID,{code:t.status,msg:t.statusText})}else if(3===t.readyState&&t.status>=200&&t.status<=299){this._status=h.LoaderStatus.kBuffering;var s=t.response;this._reader.readAsArrayBuffer(s)}}},{key:"_xhrOnError",value:function(e){this._status=h.LoaderStatus.kError;var t=h.LoaderErrors.EXCEPTION,n={code:-1,msg:e.constructor.name+" "+e.type};if(!this._onError)throw new f.RuntimeException(n.msg);this._onError(t,n)}},{key:"_msrOnProgress",value:function(e){var t=e.target,n=t.result;if(null==n)return void this._doReconnectIfNeeded();var i=n.slice(this._lastTimeBufferSize);this._lastTimeBufferSize=n.byteLength;var r=this._totalRange.from+this._receivedLength;this._receivedLength+=i.byteLength,this._onDataArrival&&this._onDataArrival(i,r,this._receivedLength),n.byteLength>=this._bufferLimit&&(d.default.v(this.TAG,"MSStream buffer exceeded max size near "+(r+i.byteLength)+", reconnecting..."),this._doReconnectIfNeeded())}},{key:"_doReconnectIfNeeded",value:function(){if(null==this._contentLength||this._receivedLength=this._contentLength&&(n=this._range.from+this._contentLength-1),this._currentRequestRange={from:t,to:n},this._internalOpen(this._dataSource,this._currentRequestRange)}},{key:"_internalOpen",value:function(e,t){this._lastTimeLoaded=0;var n=e.url;this._config.reuseRedirectedURL&&(void 0!=this._currentRedirectedURL?n=this._currentRedirectedURL:void 0!=e.redirectedURL&&(n=e.redirectedURL));var i=this._seekHandler.getConfig(n,t);this._currentRequestURL=i.url;var r=this._xhr=new XMLHttpRequest;if(r.open("GET",i.url,!0),r.responseType="arraybuffer",r.onreadystatechange=this._onReadyStateChange.bind(this),r.onprogress=this._onProgress.bind(this),r.onload=this._onLoad.bind(this),r.onerror=this._onXhrError.bind(this),e.withCredentials&&(r.withCredentials=!0),"object"===o(i.headers)){var s=i.headers;for(var a in s)s.hasOwnProperty(a)&&r.setRequestHeader(a,s[a])}r.send()}},{key:"abort",value:function(){this._requestAbort=!0,this._internalAbort(),this._status=_.LoaderStatus.kComplete}},{key:"_internalAbort",value:function(){this._xhr&&(this._xhr.onreadystatechange=null,this._xhr.onprogress=null,this._xhr.onload=null,this._xhr.onerror=null,this._xhr.abort(),this._xhr=null)}},{key:"_onReadyStateChange",value:function(e){var t=e.target;if(2===t.readyState){if(void 0!=t.responseURL){var n=this._seekHandler.removeURLParameters(t.responseURL);t.responseURL!==this._currentRequestURL&&n!==this._currentRedirectedURL&&(this._currentRedirectedURL=n,this._onURLRedirect&&this._onURLRedirect(n))}if(t.status>=200&&t.status<=299){if(this._waitForTotalLength)return;this._status=_.LoaderStatus.kBuffering}else{if(this._status=_.LoaderStatus.kError,!this._onError)throw new m.RuntimeException("RangeLoader: Http code invalid, "+t.status+" "+t.statusText);this._onError(_.LoaderErrors.HTTP_STATUS_CODE_INVALID,{code:t.status,msg:t.statusText})}}}},{key:"_onProgress",value:function(e){if(this._status!==_.LoaderStatus.kError){if(null===this._contentLength){var t=!1;if(this._waitForTotalLength){this._waitForTotalLength=!1,this._totalLengthReceived=!0,t=!0;var n=e.total;this._internalAbort(),null!=n&0!==n&&(this._totalLength=n)}if(-1===this._range.to?this._contentLength=this._totalLength-this._range.from:this._contentLength=this._range.to-this._range.from+1,t)return void this._openSubRange();this._onContentLengthKnown&&this._onContentLengthKnown(this._contentLength)}var i=e.loaded-this._lastTimeLoaded;this._lastTimeLoaded=e.loaded,this._speedSampler.addBytes(i)}}},{key:"_normalizeSpeed",value:function(e){var t=this._chunkSizeKBList,n=t.length-1,i=0,r=0,s=n;if(e=t[i]&&e=3&&(t=this._speedSampler.currentKBps),0!==t){var n=this._normalizeSpeed(t);this._currentSpeedNormalized!==n&&(this._currentSpeedNormalized=n,this._currentChunkSizeKB=n)}var i=e.target.response,r=this._range.from+this._receivedLength;this._receivedLength+=i.byteLength;var s=!1;null!=this._contentLength&&this._receivedLength0&&this._receivedLength0&&(this._requestSetTime=!0,this._mediaElement.currentTime=0),this._transmuxer=new p.default(this._mediaDataSource,this._config),this._transmuxer.on(g.default.INIT_SEGMENT,function(t,n){e._msectl.appendInitSegment(n)}),this._transmuxer.on(g.default.MEDIA_SEGMENT,function(t,n){if(e._msectl.appendMediaSegment(n),e._config.lazyLoad&&!e._config.isLive){var i=e._mediaElement.currentTime;n.info.endDts>=1e3*(i+e._config.lazyLoadMaxDuration)&&null==e._progressChecker&&(d.default.v(e.TAG,"Maximum buffering duration exceeded, suspend transmuxing task"),e._suspendTransmuxer())}}),this._transmuxer.on(g.default.LOADING_COMPLETE,function(){e._msectl.endOfStream(),e._emitter.emit(_.default.LOADING_COMPLETE)}), +this._transmuxer.on(g.default.RECOVERED_EARLY_EOF,function(){e._emitter.emit(_.default.RECOVERED_EARLY_EOF)}),this._transmuxer.on(g.default.IO_ERROR,function(t,n){e._emitter.emit(_.default.ERROR,k.ErrorTypes.NETWORK_ERROR,t,n)}),this._transmuxer.on(g.default.DEMUX_ERROR,function(t,n){e._emitter.emit(_.default.ERROR,k.ErrorTypes.MEDIA_ERROR,t,{code:-1,msg:n})}),this._transmuxer.on(g.default.MEDIA_INFO,function(t){e._mediaInfo=t,e._emitter.emit(_.default.MEDIA_INFO,Object.assign({},t))}),this._transmuxer.on(g.default.STATISTICS_INFO,function(t){e._statisticsInfo=e._fillStatisticsInfo(t),e._emitter.emit(_.default.STATISTICS_INFO,Object.assign({},e._statisticsInfo))}),this._transmuxer.on(g.default.RECOMMEND_SEEKPOINT,function(t){e._mediaElement&&!e._config.accurateSeek&&(e._requestSetTime=!0,e._mediaElement.currentTime=t/1e3)}),this._transmuxer.open()}}},{key:"unload",value:function(){this._mediaElement&&this._mediaElement.pause(),this._msectl&&this._msectl.seek(0),this._transmuxer&&(this._transmuxer.close(),this._transmuxer.destroy(),this._transmuxer=null)}},{key:"play",value:function(){return this._mediaElement.play()}},{key:"pause",value:function(){this._mediaElement.pause()}},{key:"_fillStatisticsInfo",value:function(e){if(e.playerType=this._type,!(this._mediaElement instanceof HTMLVideoElement))return e;var t=!0,n=0,i=0;if(this._mediaElement.getVideoPlaybackQuality){var r=this._mediaElement.getVideoPlaybackQuality();n=r.totalVideoFrames,i=r.droppedVideoFrames}else void 0!=this._mediaElement.webkitDecodedFrameCount?(n=this._mediaElement.webkitDecodedFrameCount,i=this._mediaElement.webkitDroppedFrameCount):t=!1;return t&&(e.decodedFrames=n,e.droppedFrames=i),e}},{key:"_onmseUpdateEnd",value:function(){if(this._config.lazyLoad&&!this._config.isLive){for(var e=this._mediaElement.buffered,t=this._mediaElement.currentTime,n=0,i=0;i=t+this._config.lazyLoadMaxDuration&&null==this._progressChecker&&(d.default.v(this.TAG,"Maximum buffering duration exceeded, suspend transmuxing task"),this._suspendTransmuxer())}}},{key:"_onmseBufferFull",value:function(){d.default.v(this.TAG,"MSE SourceBuffer is full, suspend transmuxing task"),null==this._progressChecker&&this._suspendTransmuxer()}},{key:"_suspendTransmuxer",value:function(){this._transmuxer&&(this._transmuxer.pause(),null==this._progressChecker&&(this._progressChecker=window.setInterval(this._checkProgressAndResume.bind(this),1e3)))}},{key:"_checkProgressAndResume",value:function(){for(var e=this._mediaElement.currentTime,t=this._mediaElement.buffered,n=!1,i=0;i=r&&e=s-this._config.lazyLoadRecoverDuration&&(n=!0);break}}n&&(window.clearInterval(this._progressChecker),this._progressChecker=null,n&&(d.default.v(this.TAG,"Continue loading from paused position"),this._transmuxer.resume()))}},{key:"_isTimepointBuffered",value:function(e){for(var t=this._mediaElement.buffered,n=0;n=i&&e0){var r=this._mediaElement.buffered.start(0);(r<1&&e0&&t.currentTime0){var i=n.start(0);if(i<1&&t0&&(this._mediaElement.currentTime=0),this._mediaElement.preload="auto",this._mediaElement.load(),this._statisticsReporter=window.setInterval(this._reportStatisticsInfo.bind(this),this._config.statisticsInfoReportInterval)}},{key:"unload",value:function(){this._mediaElement&&(this._mediaElement.src="",this._mediaElement.removeAttribute("src")),null!=this._statisticsReporter&&(window.clearInterval(this._statisticsReporter),this._statisticsReporter=null)}},{key:"play",value:function(){return this._mediaElement.play()}},{key:"pause",value:function(){this._mediaElement.pause()}},{key:"_onvLoadedMetadata",value:function(e){null!=this._pendingSeekTime&&(this._mediaElement.currentTime=this._pendingSeekTime,this._pendingSeekTime=null),this._emitter.emit(d.default.MEDIA_INFO,this.mediaInfo)}},{key:"_reportStatisticsInfo",value:function(){this._emitter.emit(d.default.STATISTICS_INFO,this.statisticsInfo)}},{key:"type",get:function(){return this._type}},{key:"buffered",get:function(){return this._mediaElement.buffered}},{key:"duration",get:function(){return this._mediaElement.duration}},{key:"volume",get:function(){return this._mediaElement.volume},set:function(e){this._mediaElement.volume=e}},{key:"muted",get:function(){return this._mediaElement.muted},set:function(e){this._mediaElement.muted=e}},{key:"currentTime",get:function(){return this._mediaElement?this._mediaElement.currentTime:0},set:function(e){this._mediaElement?this._mediaElement.currentTime=e:this._pendingSeekTime=e}},{key:"mediaInfo",get:function(){var e=this._mediaElement instanceof HTMLAudioElement?"audio/":"video/",t={mimeType:e+this._mediaDataSource.type};return this._mediaElement&&(t.duration=Math.floor(1e3*this._mediaElement.duration),this._mediaElement instanceof HTMLVideoElement&&(t.width=this._mediaElement.videoWidth,t.height=this._mediaElement.videoHeight)),t}},{key:"statisticsInfo",get:function(){var e={playerType:this._type,url:this._mediaDataSource.url};if(!(this._mediaElement instanceof HTMLVideoElement))return e;var t=!0,n=0,i=0;if(this._mediaElement.getVideoPlaybackQuality){var r=this._mediaElement.getVideoPlaybackQuality();n=r.totalVideoFrames,i=r.droppedVideoFrames}else void 0!=this._mediaElement.webkitDecodedFrameCount?(n=this._mediaElement.webkitDecodedFrameCount,i=this._mediaElement.webkitDroppedFrameCount):t=!1;return t&&(e.decodedFrames=n,e.droppedFrames=i),e}}]),e}();n.default=c},{"../config.js":5,"../utils/exception.js":40,"./player-events.js":35,events:2}],34:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.ErrorDetails=n.ErrorTypes=void 0;var i=e("../io/loader.js"),r=e("../demux/demux-errors.js"),s=function(e){return e&&e.__esModule?e:{default:e}}(r);n.ErrorTypes={NETWORK_ERROR:"NetworkError",MEDIA_ERROR:"MediaError",OTHER_ERROR:"OtherError"},n.ErrorDetails={NETWORK_EXCEPTION:i.LoaderErrors.EXCEPTION,NETWORK_STATUS_CODE_INVALID:i.LoaderErrors.HTTP_STATUS_CODE_INVALID,NETWORK_TIMEOUT:i.LoaderErrors.CONNECTING_TIMEOUT,NETWORK_UNRECOVERABLE_EARLY_EOF:i.LoaderErrors.UNRECOVERABLE_EARLY_EOF,MEDIA_MSE_ERROR:"MediaMSEError",MEDIA_FORMAT_ERROR:s.default.FORMAT_ERROR,MEDIA_FORMAT_UNSUPPORTED:s.default.FORMAT_UNSUPPORTED,MEDIA_CODEC_UNSUPPORTED:s.default.CODEC_UNSUPPORTED}},{"../demux/demux-errors.js":16,"../io/loader.js":24}],35:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var i={ERROR:"error",LOADING_COMPLETE:"loading_complete",RECOVERED_EARLY_EOF:"recovered_early_eof",MEDIA_INFO:"media_info",STATISTICS_INFO:"statistics_info"};n.default=i},{}],36:[function(e,t,n){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function e(e,t){for(var n=0;n>>24&255,n[1]=t>>>16&255,n[2]=t>>>8&255,n[3]=255&t,n.set(e,4);for(var a=8,o=0;o>>24&255,t>>>16&255,t>>>8&255,255&t,n>>>24&255,n>>>16&255,n>>>8&255,255&n,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255]))}},{key:"trak",value:function(t){return e.box(e.types.trak,e.tkhd(t),e.mdia(t))}},{key:"tkhd",value:function(t){var n=t.id,i=t.duration,r=t.presentWidth,s=t.presentHeight;return e.box(e.types.tkhd,new Uint8Array([0,0,0,7,0,0,0,0,0,0,0,0,n>>>24&255,n>>>16&255,n>>>8&255,255&n,0,0,0,0,i>>>24&255,i>>>16&255,i>>>8&255,255&i,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,r>>>8&255,255&r,0,0,s>>>8&255,255&s,0,0]))}},{key:"mdia",value:function(t){return e.box(e.types.mdia,e.mdhd(t),e.hdlr(t),e.minf(t))}},{key:"mdhd",value:function(t){var n=t.timescale,i=t.duration;return e.box(e.types.mdhd,new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,n>>>24&255,n>>>16&255,n>>>8&255,255&n,i>>>24&255,i>>>16&255,i>>>8&255,255&i,85,196,0,0]))}},{key:"hdlr",value:function(t){var n=null;return n="audio"===t.type?e.constants.HDLR_AUDIO:e.constants.HDLR_VIDEO,e.box(e.types.hdlr,n)}},{key:"minf",value:function(t){var n=null;return n="audio"===t.type?e.box(e.types.smhd,e.constants.SMHD):e.box(e.types.vmhd,e.constants.VMHD),e.box(e.types.minf,n,e.dinf(),e.stbl(t))}},{key:"dinf",value:function(){return e.box(e.types.dinf,e.box(e.types.dref,e.constants.DREF))}},{key:"stbl",value:function(t){return e.box(e.types.stbl,e.stsd(t),e.box(e.types.stts,e.constants.STTS),e.box(e.types.stsc,e.constants.STSC),e.box(e.types.stsz,e.constants.STSZ),e.box(e.types.stco,e.constants.STCO))}},{key:"stsd",value:function(t){return"audio"===t.type?"mp3"===t.codec?e.box(e.types.stsd,e.constants.STSD_PREFIX,e.mp3(t)):e.box(e.types.stsd,e.constants.STSD_PREFIX,e.mp4a(t)):e.box(e.types.stsd,e.constants.STSD_PREFIX,e.avc1(t))}},{key:"mp3",value:function(t){var n=t.channelCount,i=t.audioSampleRate,r=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,n,0,16,0,0,0,0,i>>>8&255,255&i,0,0]);return e.box(e.types[".mp3"],r)}},{key:"mp4a",value:function(t){var n=t.channelCount,i=t.audioSampleRate,r=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,n,0,16,0,0,0,0,i>>>8&255,255&i,0,0]);return e.box(e.types.mp4a,r,e.esds(t))}},{key:"esds",value:function(t){var n=t.config||[],i=n.length,r=new Uint8Array([0,0,0,0,3,23+i,0,1,0,4,15+i,64,21,0,0,0,0,0,0,0,0,0,0,0,5].concat([i]).concat(n).concat([6,1,2]));return e.box(e.types.esds,r)}},{key:"avc1",value:function(t){var n=t.avcc,i=t.codecWidth,r=t.codecHeight,s=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,i>>>8&255,255&i,r>>>8&255,255&r,0,72,0,0,0,72,0,0,0,0,0,0,0,1,10,120,113,113,47,102,108,118,46,106,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,255,255]);return e.box(e.types.avc1,s,e.box(e.types.avcC,n))}},{key:"mvex",value:function(t){return e.box(e.types.mvex,e.trex(t))}},{key:"trex",value:function(t){var n=t.id,i=new Uint8Array([0,0,0,0,n>>>24&255,n>>>16&255,n>>>8&255,255&n,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1]);return e.box(e.types.trex,i)}},{key:"moof",value:function(t,n){return e.box(e.types.moof,e.mfhd(t.sequenceNumber),e.traf(t,n))}},{key:"mfhd",value:function(t){var n=new Uint8Array([0,0,0,0,t>>>24&255,t>>>16&255,t>>>8&255,255&t]);return e.box(e.types.mfhd,n)}},{key:"traf",value:function(t,n){var i=t.id,r=e.box(e.types.tfhd,new Uint8Array([0,0,0,0,i>>>24&255,i>>>16&255,i>>>8&255,255&i])),s=e.box(e.types.tfdt,new Uint8Array([0,0,0,0,n>>>24&255,n>>>16&255,n>>>8&255,255&n])),a=e.sdtp(t),o=e.trun(t,a.byteLength+16+16+8+16+8+8);return e.box(e.types.traf,r,s,o,a)}},{key:"sdtp",value:function(t){for(var n=t.samples||[],i=n.length,r=new Uint8Array(4+i),s=0;s>>24&255,r>>>16&255,r>>>8&255,255&r,n>>>24&255,n>>>16&255,n>>>8&255,255&n],0);for(var o=0;o>>24&255,u>>>16&255,u>>>8&255,255&u,l>>>24&255,l>>>16&255,l>>>8&255,255&l,d.isLeading<<2|d.dependsOn,d.isDependedOn<<6|d.hasRedundancy<<4|d.isNonSync,0,0,h>>>24&255,h>>>16&255,h>>>8&255,255&h],12+16*o)}return e.box(e.types.trun,a)}},{key:"mdat",value:function(t){return e.box(e.types.mdat,t)}}]),e}();s.init(),n.default=s},{}],38:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var s=function(){function e(e,t){for(var n=0;n1&&(y=i.pop(),g-=y.length),null!=this._audioStashedLastSample){var E=this._audioStashedLastSample;this._audioStashedLastSample=null,i.unshift(E),g+=E.length}null!=y&&(this._audioStashedLastSample=y);var b=i[0].dts-this._dtsBase;if(this._audioNextDts)r=b-this._audioNextDts;else if(this._audioSegmentInfoList.isEmpty())r=0,this._fillSilentAfterSeek&&!this._videoSegmentInfoList.isEmpty()&&"mp3"!==this._audioMeta.originalCodec&&(m=!0);else{var S=this._audioSegmentInfoList.getLastSampleBefore(b);if(null!=S){var k=b-(S.originalDts+S.duration);k<=3&&(k=0);var L=S.dts+S.duration+k;r=b-L}else r=0}if(m){var w=b-r,R=this._videoSegmentInfoList.getLastSegmentBefore(b);if(null!=R&&R.beginDts=1?C[C.length-1].duration:Math.floor(u);var U=!1,N=null;if(j>1.5*u&&"mp3"!==this._audioMeta.codec&&this._fillAudioTimestampGap&&!c.default.safari){U=!0;var F=Math.abs(j-u),G=Math.ceil(F/u),V=B+u;o.default.w(this.TAG,"Large audio timestamp gap detected, may cause AV sync to drift. Silent frames will be generated to avoid unsync.\ndts: "+(B+j)+" ms, expected: "+(B+Math.round(u))+" ms, delta: "+Math.round(F)+" ms, generate: "+G+" frames");var z=h.default.getSilentFrame(this._audioMeta.originalCodec,this._audioMeta.channelCount);null==z&&(o.default.w(this.TAG,"Unable to generate silent frame for "+this._audioMeta.originalCodec+" with "+this._audioMeta.channelCount+" channels, repeat last frame"),z=M),N=[];for(var H=0;H0){var q=N[N.length-1];q.duration=K-q.dts}var W={dts:K,pts:K,cts:0,unit:z,size:z.byteLength,duration:0,originalDts:D,flags:{isLeading:0,dependsOn:1,isDependedOn:0,hasRedundancy:0}};N.push(W),g+=M.byteLength,V+=u}var X=N[N.length-1];X.duration=B+j-X.dts,j=Math.round(u)}C.push({dts:B,pts:B,cts:0,unit:x.unit,size:x.unit.byteLength,duration:j,originalDts:D,flags:{isLeading:0,dependsOn:1,isDependedOn:0,hasRedundancy:0}}),U&&C.push.apply(C,N)}d?v=new Uint8Array(g):(v=new Uint8Array(g),v[0]=g>>>24&255,v[1]=g>>>16&255,v[2]=g>>>8&255,v[3]=255&g,v.set(l.default.types.mdat,4));for(var Y=0;Y1&&(c=i.pop(),f-=c.length),null!=this._videoStashedLastSample){var m=this._videoStashedLastSample;this._videoStashedLastSample=null,i.unshift(m),f+=m.length}null!=c&&(this._videoStashedLastSample=c);var p=i[0].dts-this._dtsBase;if(this._videoNextDts)r=p-this._videoNextDts;else if(this._videoSegmentInfoList.isEmpty())r=0;else{var v=this._videoSegmentInfoList.getLastSampleBefore(p);if(null!=v){var g=p-(v.originalDts+v.duration);g<=3&&(g=0);var y=v.dts+v.duration+g;r=p-y}else r=0}for(var E=new _.MediaSegmentInfo,b=[],S=0;S=1?b[b.length-1].duration:Math.floor(this._videoMeta.refSampleDuration);if(w){var I=new _.SampleInfo(R,O,T,k.dts,!0);I.fileposition=k.fileposition,E.appendSyncPoint(I)}b.push({dts:R,pts:O,cts:A,units:k.units,size:k.length,isKeyframe:w,duration:T,originalDts:L,flags:{isLeading:0,dependsOn:w?2:1,isDependedOn:w?1:0,hasRedundancy:0,isNonSync:w?0:1}})}h=new Uint8Array(f),h[0]=f>>>24&255,h[1]=f>>>16&255,h[2]=f>>>8&255,h[3]=255&f,h.set(l.default.types.mdat,4);for(var x=0;x=0&&/(rv)(?::| )([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(firefox)[ \/]([\w.]+)/.exec(e)||[],n=/(ipad)/.exec(e)||/(ipod)/.exec(e)||/(windows phone)/.exec(e)||/(iphone)/.exec(e)||/(kindle)/.exec(e)||/(android)/.exec(e)||/(windows)/.exec(e)||/(mac)/.exec(e)||/(linux)/.exec(e)||/(cros)/.exec(e)||[],r={browser:t[5]||t[3]||t[1]||"",version:t[2]||t[4]||"0",majorVersion:t[4]||t[2]||"0",platform:n[0]||""},s={};if(r.browser){s[r.browser]=!0;var a=r.majorVersion.split(".");s.version={major:parseInt(r.majorVersion,10),string:r.version},a.length>1&&(s.version.minor=parseInt(a[1],10)),a.length>2&&(s.version.build=parseInt(a[2],10))}r.platform&&(s[r.platform]=!0),(s.chrome||s.opr||s.safari)&&(s.webkit=!0),(s.rv||s.iemobile)&&(s.rv&&delete s.rv,r.browser="msie",s.msie=!0),s.edge&&(delete s.edge,r.browser="msedge",s.msedge=!0),s.opr&&(r.browser="opera",s.opera=!0),s.safari&&s.android&&(r.browser="android",s.android=!0),s.name=r.browser,s.platform=r.platform;for(var o in i)i.hasOwnProperty(o)&&delete i[o];Object.assign(i,s)}(),n.default=i},{}],40:[function(e,t,n){"use strict";function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var a=function(){function e(e,t){for(var n=0;n "+n;e.ENABLE_CALLBACK&&e.emitter.emit("log","error",i),e.ENABLE_ERROR&&(console.error?console.error(i):console.warn?console.warn(i):console.log(i))}},{key:"i",value:function(t,n){t&&!e.FORCE_GLOBAL_TAG||(t=e.GLOBAL_TAG);var i="["+t+"] > "+n;e.ENABLE_CALLBACK&&e.emitter.emit("log","info",i),e.ENABLE_INFO&&(console.info?console.info(i):console.log(i))}},{key:"w",value:function(t,n){t&&!e.FORCE_GLOBAL_TAG||(t=e.GLOBAL_TAG);var i="["+t+"] > "+n;e.ENABLE_CALLBACK&&e.emitter.emit("log","warn",i),e.ENABLE_WARN&&(console.warn?console.warn(i):console.log(i))}},{key:"d",value:function(t,n){t&&!e.FORCE_GLOBAL_TAG||(t=e.GLOBAL_TAG);var i="["+t+"] > "+n;e.ENABLE_CALLBACK&&e.emitter.emit("log","debug",i),e.ENABLE_DEBUG&&(console.debug?console.debug(i):console.log(i))}},{key:"v",value:function(t,n){t&&!e.FORCE_GLOBAL_TAG||(t=e.GLOBAL_TAG);var i="["+t+"] > "+n;e.ENABLE_CALLBACK&&e.emitter.emit("log","verbose",i),e.ENABLE_VERBOSE&&console.log(i)}}]),e}();o.GLOBAL_TAG="flv.js",o.FORCE_GLOBAL_TAG=!1,o.ENABLE_ERROR=!0,o.ENABLE_INFO=!0,o.ENABLE_WARN=!0,o.ENABLE_DEBUG=!0,o.ENABLE_VERBOSE=!0,o.ENABLE_CALLBACK=!1,o.emitter=new a.default,n.default=o},{events:2}],42:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var s=function(){function e(e,t){for(var n=0;n0){var n=e.getConfig();t.emit("change",n)}}},{key:"registerListener",value:function(t){e.emitter.addListener("change",t)}},{key:"removeListener",value:function(t){e.emitter.removeListener("change",t)}},{key:"addLogListener",value:function(t){l.default.emitter.addListener("log",t),l.default.emitter.listenerCount("log")>0&&(l.default.ENABLE_CALLBACK=!0,e._notifyChange())}},{key:"removeLogListener",value:function(t){l.default.emitter.removeListener("log",t),0===l.default.emitter.listenerCount("log")&&(l.default.ENABLE_CALLBACK=!1,e._notifyChange())}},{key:"forceGlobalTag",get:function(){return l.default.FORCE_GLOBAL_TAG},set:function(t){l.default.FORCE_GLOBAL_TAG=t,e._notifyChange()}},{key:"globalTag",get:function(){return l.default.GLOBAL_TAG},set:function(t){l.default.GLOBAL_TAG=t,e._notifyChange()}},{key:"enableAll",get:function(){return l.default.ENABLE_VERBOSE&&l.default.ENABLE_DEBUG&&l.default.ENABLE_INFO&&l.default.ENABLE_WARN&&l.default.ENABLE_ERROR},set:function(t){l.default.ENABLE_VERBOSE=t,l.default.ENABLE_DEBUG=t,l.default.ENABLE_INFO=t,l.default.ENABLE_WARN=t,l.default.ENABLE_ERROR=t,e._notifyChange()}},{key:"enableDebug",get:function(){return l.default.ENABLE_DEBUG},set:function(t){l.default.ENABLE_DEBUG=t,e._notifyChange()}},{key:"enableVerbose",get:function(){return l.default.ENABLE_VERBOSE},set:function(t){l.default.ENABLE_VERBOSE=t,e._notifyChange()}},{key:"enableInfo",get:function(){return l.default.ENABLE_INFO},set:function(t){l.default.ENABLE_INFO=t,e._notifyChange()}},{key:"enableWarn",get:function(){return l.default.ENABLE_WARN},set:function(t){l.default.ENABLE_WARN=t,e._notifyChange()}},{key:"enableError",get:function(){return l.default.ENABLE_ERROR},set:function(t){l.default.ENABLE_ERROR=t,e._notifyChange()}}]),e}();d.emitter=new o.default,n.default=d},{"./logger.js":41,events:2}],43:[function(e,t,n){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function e(e,t){for(var n=0;n=128){t.push(String.fromCharCode(65535&a)),r+=2;continue}}}else if(n[r]<240){if(i(n,r,2)){var o=(15&n[r])<<12|(63&n[r+1])<<6|63&n[r+2];if(o>=2048&&55296!=(63488&o)){t.push(String.fromCharCode(65535&o)),r+=3;continue}}}else if(n[r]<248&&i(n,r,3)){var u=(7&n[r])<<18|(63&n[r+1])<<12|(63&n[r+2])<<6|63&n[r+3];if(u>65536&&u<1114112){u-=65536,t.push(String.fromCharCode(u>>>10|55296)),t.push(String.fromCharCode(1023&u|56320)),r+=4;continue}}t.push(String.fromCharCode(65533)),++r}return t.join("")}Object.defineProperty(n,"__esModule",{value:!0}),n.default=r},{}]},{},[21])(21)}); +//# sourceMappingURL=flv.min.js.map diff --git a/src/bower_components/emby-webcomponents/focusmanager.js b/src/bower_components/emby-webcomponents/focusmanager.js index c80ca2e3a3..5977dc0715 100644 --- a/src/bower_components/emby-webcomponents/focusmanager.js +++ b/src/bower_components/emby-webcomponents/focusmanager.js @@ -1,249 +1,544 @@ -define(["dom"], function(dom) { - "use strict"; +define(['dom'], function (dom) { + 'use strict'; + var scopes = []; function pushScope(elem) { - scopes.push(elem) + scopes.push(elem); } function popScope(elem) { - scopes.length && (scopes.length -= 1) - } - function autoFocus(view, defaultToFirst, findAutoFocusElement) { - var element; - return !1 !== findAutoFocusElement && (element = view.querySelector("*[autofocus]")) ? (focus(element), element) : !1 !== defaultToFirst && (element = getFocusableElements(view, 1, "noautofocus")[0]) ? (focus(element), element) : null - } - - function focus(element) { - try { - element.focus({ - preventScroll: !0 - }) - } catch (err) { - console.log("Error in focusManager.autoFocus: " + err) + if (scopes.length) { + scopes.length -= 1; } } + function autoFocus(view, defaultToFirst, findAutoFocusElement) { + + var element; + if (findAutoFocusElement !== false) { + element = view.querySelector('*[autofocus]'); + if (element) { + focus(element); + return element; + } + } + + if (defaultToFirst !== false) { + element = getFocusableElements(view, 1, 'noautofocus')[0]; + + if (element) { + focus(element); + return element; + } + } + + return null; + } + + function focus(element) { + + try { + element.focus({ + preventScroll: true + }); + } catch (err) { + console.log('Error in focusManager.autoFocus: ' + err); + } + } + + var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A']; + var focusableContainerTagNames = ['BODY', 'DIALOG']; + var focusableQuery = focusableTagNames.map(function (t) { + + if (t === 'INPUT') { + t += ':not([type="range"]):not([type="file"])'; + } + return t + ':not([tabindex="-1"]):not(:disabled)'; + + }).join(',') + ',.focusable'; + function isFocusable(elem) { - return -1 !== focusableTagNames.indexOf(elem.tagName) || !(!elem.classList || !elem.classList.contains("focusable")) + + if (focusableTagNames.indexOf(elem.tagName) !== -1) { + return true; + } + + if (elem.classList && elem.classList.contains('focusable')) { + return true; + } + + return false; } function normalizeFocusable(elem, originalElement) { if (elem) { var tagName = elem.tagName; - tagName && "HTML" !== tagName && "BODY" !== tagName || (elem = originalElement) + if (!tagName || tagName === 'HTML' || tagName === 'BODY') { + elem = originalElement; + } } - return elem + + return elem; } function focusableParent(elem) { - for (var originalElement = elem; !isFocusable(elem);) { + + var originalElement = elem; + + while (!isFocusable(elem)) { var parent = elem.parentNode; - if (!parent) return normalizeFocusable(elem, originalElement); - elem = parent + + if (!parent) { + return normalizeFocusable(elem, originalElement); + } + + elem = parent; } - return normalizeFocusable(elem, originalElement) + + return normalizeFocusable(elem, originalElement); } + // Determines if a focusable element can be focused at a given point in time function isCurrentlyFocusableInternal(elem) { - return null !== elem.offsetParent + + // http://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom + if (elem.offsetParent === null) { + return false; + } + + return true; } + // Determines if a focusable element can be focused at a given point in time function isCurrentlyFocusable(elem) { - if (elem.disabled) return !1; - if ("-1" === elem.getAttribute("tabindex")) return !1; - if ("INPUT" === elem.tagName) { - var type = elem.type; - if ("range" === type) return !1; - if ("file" === type) return !1 + + if (elem.disabled) { + return false; } - return isCurrentlyFocusableInternal(elem) + + if (elem.getAttribute('tabindex') === "-1") { + return false; + } + + if (elem.tagName === 'INPUT') { + var type = elem.type; + if (type === 'range') { + return false; + } + if (type === 'file') { + return false; + } + } + + return isCurrentlyFocusableInternal(elem); } function getDefaultScope() { - return scopes[0] || document.body + return scopes[0] || document.body; } function getFocusableElements(parent, limit, excludeClass) { - for (var elems = (parent || getDefaultScope()).querySelectorAll(focusableQuery), focusableElements = [], i = 0, length = elems.length; i < length; i++) { + var elems = (parent || getDefaultScope()).querySelectorAll(focusableQuery); + var focusableElements = []; + + for (var i = 0, length = elems.length; i < length; i++) { + var elem = elems[i]; - if ((!excludeClass || !elem.classList.contains(excludeClass)) && (isCurrentlyFocusableInternal(elem) && (focusableElements.push(elem), limit && focusableElements.length >= limit))) break + + if (excludeClass && elem.classList.contains(excludeClass)) { + continue; + } + + if (isCurrentlyFocusableInternal(elem)) { + focusableElements.push(elem); + + if (limit && focusableElements.length >= limit) { + break; + } + } } - return focusableElements + + return focusableElements; } function isFocusContainer(elem, direction) { - if (-1 !== focusableContainerTagNames.indexOf(elem.tagName)) return !0; - var classList = elem.classList; - if (classList.contains("focuscontainer")) return !0; - if (0 === direction) { - if (classList.contains("focuscontainer-x")) return !0; - if (classList.contains("focuscontainer-left")) return !0 - } else if (1 === direction) { - if (classList.contains("focuscontainer-x")) return !0; - if (classList.contains("focuscontainer-right")) return !0 - } else if (2 === direction) { - if (classList.contains("focuscontainer-y")) return !0 - } else if (3 === direction) { - if (classList.contains("focuscontainer-y")) return !0; - if (classList.contains("focuscontainer-down")) return !0 + + if (focusableContainerTagNames.indexOf(elem.tagName) !== -1) { + return true; } - return !1 + + var classList = elem.classList; + + if (classList.contains('focuscontainer')) { + return true; + } + + if (direction === 0) { + if (classList.contains('focuscontainer-x')) { + return true; + } + if (classList.contains('focuscontainer-left')) { + return true; + } + } + else if (direction === 1) { + if (classList.contains('focuscontainer-x')) { + return true; + } + if (classList.contains('focuscontainer-right')) { + return true; + } + } + else if (direction === 2) { + if (classList.contains('focuscontainer-y')) { + return true; + } + } + else if (direction === 3) { + if (classList.contains('focuscontainer-y')) { + return true; + } + if (classList.contains('focuscontainer-down')) { + return true; + } + } + + return false; } function getFocusContainer(elem, direction) { - for (; !isFocusContainer(elem, direction);) - if (!(elem = elem.parentNode)) return getDefaultScope(); - return elem + while (!isFocusContainer(elem, direction)) { + elem = elem.parentNode; + + if (!elem) { + return getDefaultScope(); + } + } + + return elem; } function getOffset(elem) { + var box; - if (box = elem.getBoundingClientRect ? elem.getBoundingClientRect() : { + + // Support: BlackBerry 5, iOS 3 (original iPhone) + // If we don't have gBCR, just use 0,0 rather than error + if (elem.getBoundingClientRect) { + box = elem.getBoundingClientRect(); + } else { + box = { top: 0, left: 0, width: 0, height: 0 - }, null === box.right) { - box = { + }; + } + + if (box.right === null) { + + // Create a new object because some browsers will throw an error when trying to set data onto the Rect object + var newBox = { top: box.top, left: box.left, width: box.width, height: box.height - }, box.right = box.left + box.width, box.bottom = box.top + box.height + }; + + box = newBox; + + box.right = box.left + box.width; + box.bottom = box.top + box.height; } - return box + + return box; } function nav(activeElement, direction, container, focusableElements) { - if (activeElement = activeElement || document.activeElement, activeElement && (activeElement = focusableParent(activeElement)), container = container || (activeElement ? getFocusContainer(activeElement, direction) : getDefaultScope()), !activeElement) return void autoFocus(container, !0, !1); - for (var nearestElement, focusableContainer = dom.parentWithClass(activeElement, "focusable"), rect = getOffset(activeElement), point1x = parseFloat(rect.left) || 0, point1y = parseFloat(rect.top) || 0, point2x = parseFloat(point1x + rect.width - 1) || point1x, point2y = parseFloat(point1y + rect.height - 1) || point1y, sourceMidX = (Math.min, Math.max, rect.left + rect.width / 2), sourceMidY = rect.top + rect.height / 2, focusable = focusableElements || container.querySelectorAll(focusableQuery), minDistance = 1 / 0, i = 0, length = focusable.length; i < length; i++) { + + activeElement = activeElement || document.activeElement; + + if (activeElement) { + activeElement = focusableParent(activeElement); + } + + container = container || (activeElement ? getFocusContainer(activeElement, direction) : getDefaultScope()); + + if (!activeElement) { + autoFocus(container, true, false); + return; + } + + var focusableContainer = dom.parentWithClass(activeElement, 'focusable'); + + var rect = getOffset(activeElement); + + // Get elements and work out x/y points + var cache = [], + point1x = parseFloat(rect.left) || 0, + point1y = parseFloat(rect.top) || 0, + point2x = parseFloat(point1x + rect.width - 1) || point1x, + point2y = parseFloat(point1y + rect.height - 1) || point1y, + // Shortcuts to help with compression + min = Math.min, + max = Math.max; + + var sourceMidX = rect.left + (rect.width / 2); + var sourceMidY = rect.top + (rect.height / 2); + + var focusable = focusableElements || container.querySelectorAll(focusableQuery); + + var maxDistance = Infinity; + var minDistance = maxDistance; + var nearestElement; + + for (var i = 0, length = focusable.length; i < length; i++) { var curr = focusable[i]; - if (curr !== activeElement && curr !== focusableContainer) { - var elementRect = getOffset(curr); - if (elementRect.width || elementRect.height) { - switch (direction) { - case 0: - if (elementRect.left >= rect.left) continue; - if (elementRect.right === rect.right) continue; - break; - case 1: - if (elementRect.right <= rect.right) continue; - if (elementRect.left === rect.left) continue; - break; - case 2: - if (elementRect.top >= rect.top) continue; - if (elementRect.bottom >= rect.bottom) continue; - break; - case 3: - if (elementRect.bottom <= rect.bottom) continue; - if (elementRect.top <= rect.top) continue + + if (curr === activeElement) { + continue; + } + // Don't refocus into the same container + if (curr === focusableContainer) { + continue; + } + + //if (!isCurrentlyFocusableInternal(curr)) { + // continue; + //} + + var elementRect = getOffset(curr); + + // not currently visible + if (!elementRect.width && !elementRect.height) { + continue; + } + + switch (direction) { + + case 0: + // left + if (elementRect.left >= rect.left) { + continue; } - var distX, distY, x = elementRect.left, - y = elementRect.top, - x2 = x + elementRect.width - 1, - y2 = y + elementRect.height - 1, - intersectX = intersects(point1x, point2x, x, x2), - intersectY = intersects(point1y, point2y, y, y2), - midX = elementRect.left + elementRect.width / 2, - midY = elementRect.top + elementRect.height / 2; - switch (direction) { - case 0: - distX = Math.abs(point1x - Math.min(point1x, x2)), distY = intersectY ? 0 : Math.abs(sourceMidY - midY); - break; - case 1: - distX = Math.abs(point2x - Math.max(point2x, x)), distY = intersectY ? 0 : Math.abs(sourceMidY - midY); - break; - case 2: - distY = Math.abs(point1y - Math.min(point1y, y2)), distX = intersectX ? 0 : Math.abs(sourceMidX - midX); - break; - case 3: - distY = Math.abs(point2y - Math.max(point2y, y)), distX = intersectX ? 0 : Math.abs(sourceMidX - midX) + if (elementRect.right === rect.right) { + continue; } - var dist = Math.sqrt(distX * distX + distY * distY); - dist < minDistance && (nearestElement = curr, minDistance = dist) - } + break; + case 1: + // right + if (elementRect.right <= rect.right) { + continue; + } + if (elementRect.left === rect.left) { + continue; + } + break; + case 2: + // up + if (elementRect.top >= rect.top) { + continue; + } + if (elementRect.bottom >= rect.bottom) { + continue; + } + break; + case 3: + // down + if (elementRect.bottom <= rect.bottom) { + continue; + } + if (elementRect.top <= rect.top) { + continue; + } + break; + default: + break; + } + + var x = elementRect.left, + y = elementRect.top, + x2 = x + elementRect.width - 1, + y2 = y + elementRect.height - 1; + + var intersectX = intersects(point1x, point2x, x, x2); + var intersectY = intersects(point1y, point2y, y, y2); + + var midX = elementRect.left + (elementRect.width / 2); + var midY = elementRect.top + (elementRect.height / 2); + + var distX; + var distY; + + switch (direction) { + + case 0: + // left + distX = Math.abs(point1x - Math.min(point1x, x2)); + distY = intersectY ? 0 : Math.abs(sourceMidY - midY); + break; + case 1: + // right + distX = Math.abs(point2x - Math.max(point2x, x)); + distY = intersectY ? 0 : Math.abs(sourceMidY - midY); + break; + case 2: + // up + distY = Math.abs(point1y - Math.min(point1y, y2)); + distX = intersectX ? 0 : Math.abs(sourceMidX - midX); + break; + case 3: + // down + distY = Math.abs(point2y - Math.max(point2y, y)); + distX = intersectX ? 0 : Math.abs(sourceMidX - midX); + break; + default: + break; + } + + var dist = Math.sqrt(distX * distX + distY * distY); + + if (dist < minDistance) { + nearestElement = curr; + minDistance = dist; } } + if (nearestElement) { + + // See if there's a focusable container, and if so, send the focus command to that if (activeElement) { - var nearestElementFocusableParent = dom.parentWithClass(nearestElement, "focusable"); - nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement && focusableContainer !== nearestElementFocusableParent && (nearestElement = nearestElementFocusableParent) + var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable'); + if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement) { + if (focusableContainer !== nearestElementFocusableParent) { + nearestElement = nearestElementFocusableParent; + } + } } - focus(nearestElement) + focus(nearestElement); } } function intersectsInternal(a1, a2, b1, b2) { - return b1 >= a1 && b1 <= a2 || b2 >= a1 && b2 <= a2 + + return (b1 >= a1 && b1 <= a2) || (b2 >= a1 && b2 <= a2); } function intersects(a1, a2, b1, b2) { - return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2) + + return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2); } function sendText(text) { - document.activeElement.value = text + var elem = document.activeElement; + + elem.value = text; } function focusFirst(container, focusableSelector) { - for (var elems = container.querySelectorAll(focusableSelector), i = 0, length = elems.length; i < length; i++) { + + var elems = container.querySelectorAll(focusableSelector); + + for (var i = 0, length = elems.length; i < length; i++) { + var elem = elems[i]; + if (isCurrentlyFocusableInternal(elem)) { focus(elem); - break + break; } } } function focusLast(container, focusableSelector) { - for (var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse(), i = 0, length = elems.length; i < length; i++) { + + var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse(); + + for (var i = 0, length = elems.length; i < length; i++) { + var elem = elems[i]; + if (isCurrentlyFocusableInternal(elem)) { focus(elem); - break + break; } } } function moveFocus(sourceElement, container, focusableSelector, offset) { - var i, length, elem, elems = container.querySelectorAll(focusableSelector), - list = []; - for (i = 0, length = elems.length; i < length; i++) elem = elems[i], isCurrentlyFocusableInternal(elem) && list.push(elem); + + var elems = container.querySelectorAll(focusableSelector); + var list = []; + var i, length, elem; + + for (i = 0, length = elems.length; i < length; i++) { + + elem = elems[i]; + + if (isCurrentlyFocusableInternal(elem)) { + list.push(elem); + } + } + var currentIndex = -1; - for (i = 0, length = list.length; i < length; i++) - if (elem = list[i], sourceElement === elem || elem.contains(sourceElement)) { + + for (i = 0, length = list.length; i < length; i++) { + + elem = list[i]; + + if (sourceElement === elem || elem.contains(sourceElement)) { currentIndex = i; - break - } if (-1 !== currentIndex) { - var newIndex = currentIndex + offset; - newIndex = Math.max(0, newIndex), newIndex = Math.min(newIndex, list.length - 1); - var newElem = list[newIndex]; - newElem && focus(newElem) + break; + } + } + + if (currentIndex === -1) { + return; + } + + var newIndex = currentIndex + offset; + newIndex = Math.max(0, newIndex); + newIndex = Math.min(newIndex, list.length - 1); + + var newElem = list[newIndex]; + if (newElem) { + focus(newElem); } } - var scopes = [], - focusableTagNames = ["INPUT", "TEXTAREA", "SELECT", "BUTTON", "A"], - focusableContainerTagNames = ["BODY", "DIALOG"], - focusableQuery = focusableTagNames.map(function(t) { - return "INPUT" === t && (t += ':not([type="range"]):not([type="file"])'), t + ':not([tabindex="-1"]):not(:disabled)' - }).join(",") + ",.focusable"; + return { autoFocus: autoFocus, focus: focus, focusableParent: focusableParent, getFocusableElements: getFocusableElements, - moveLeft: function(sourceElement, options) { - nav(sourceElement, 0, options ? options.container : null, options ? options.focusableElements : null) + moveLeft: function (sourceElement, options) { + + var container = options ? options.container : null; + var focusableElements = options ? options.focusableElements : null; + nav(sourceElement, 0, container, focusableElements); + }, - moveRight: function(sourceElement, options) { - nav(sourceElement, 1, options ? options.container : null, options ? options.focusableElements : null) + moveRight: function (sourceElement, options) { + + var container = options ? options.container : null; + var focusableElements = options ? options.focusableElements : null; + nav(sourceElement, 1, container, focusableElements); + }, - moveUp: function(sourceElement, options) { - nav(sourceElement, 2, options ? options.container : null, options ? options.focusableElements : null) + moveUp: function (sourceElement, options) { + + var container = options ? options.container : null; + var focusableElements = options ? options.focusableElements : null; + nav(sourceElement, 2, container, focusableElements); + }, - moveDown: function(sourceElement, options) { - nav(sourceElement, 3, options ? options.container : null, options ? options.focusableElements : null) + moveDown: function (sourceElement, options) { + + var container = options ? options.container : null; + var focusableElements = options ? options.focusableElements : null; + nav(sourceElement, 3, container, focusableElements); + }, sendText: sendText, isCurrentlyFocusable: isCurrentlyFocusable, @@ -252,5 +547,5 @@ define(["dom"], function(dom) { focusFirst: focusFirst, focusLast: focusLast, moveFocus: moveFocus - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/fonts/fonts.css b/src/bower_components/emby-webcomponents/fonts/fonts.css index 112441ad18..12f1eaf4b7 100644 --- a/src/bower_components/emby-webcomponents/fonts/fonts.css +++ b/src/bower_components/emby-webcomponents/fonts/fonts.css @@ -1,39 +1,37 @@ -h1, -h2, -h3 { - font-weight: 500 +html { + font-family: -apple-system, "Helvetica", system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", 'Open Sans', sans-serif; } html { - font-family: -apple-system, Helvetica, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", 'Open Sans', sans-serif; font-size: 93%; -webkit-text-size-adjust: 100%; - -moz-text-size-adjust: 100%; - text-size-adjust: 100% + text-size-adjust: 100%; } -h1, -h2, -h3 { - font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", 'Open Sans', sans-serif +h1, h2, h3 { + /* For better bolding, since Helvetica does not support 500 weight, and 600 is too thick */ + font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", 'Open Sans', sans-serif; } h1 { - font-size: 1.8em + font-weight: 500; + font-size: 1.8em; } h2 { - font-size: 1.5em + font-weight: 500; + font-size: 1.5em; } h3 { - font-size: 1.17em + font-weight: 500; + font-size: 1.17em; } .layout-tv { - font-size: 2.5vh + font-size: 2.5vh; } .layout-mobile { - font-size: 90% -} \ No newline at end of file + font-size: 90%; +} diff --git a/src/bower_components/emby-webcomponents/fonts/fonts.sized.css b/src/bower_components/emby-webcomponents/fonts/fonts.sized.css index f8722d0016..073b74167c 100644 --- a/src/bower_components/emby-webcomponents/fonts/fonts.sized.css +++ b/src/bower_components/emby-webcomponents/fonts/fonts.sized.css @@ -1,33 +1,32 @@ -h1, -h2, -h3 { - font-weight: 500 -} - h1 { - font-size: 1.8em + font-weight: 500; + font-size: 1.8em; } .layout-desktop h1 { - font-size: 2em + font-size: 2em; } h2 { - font-size: 1.5em + font-weight: 500; + font-size: 1.5em; } h3 { - font-size: 1.17em + font-weight: 500; + font-size: 1.17em; } -@media all and (min-height:720px) { +@media all and (min-height: 720px) { html { - font-size: 20px + font-size: 20px; } } -@media all and (min-height:1000px) { +/* This is supposed to be 1080p, but had to reduce the min height to account for possible browser chrome */ +@media all and (min-height: 1000px) { + html { - font-size: 27px + font-size: 27px; } -} \ No newline at end of file +} diff --git a/src/bower_components/emby-webcomponents/fonts/material-icons/style.css b/src/bower_components/emby-webcomponents/fonts/material-icons/style.css index bcaf041b93..2d410b9985 100644 --- a/src/bower_components/emby-webcomponents/fonts/material-icons/style.css +++ b/src/bower_components/emby-webcomponents/fonts/material-icons/style.css @@ -2,12 +2,12 @@ font-family: 'Material Icons'; font-style: normal; font-weight: 400; - src: local('Material Icons'), local('MaterialIcons-Regular'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff) format('woff') + src: local('Material Icons'), local('MaterialIcons-Regular'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff) format('woff'); } .md-icon { font-family: 'Material Icons'; - font-weight: 400; + font-weight: normal; font-style: normal; letter-spacing: normal; text-transform: none; @@ -15,12 +15,11 @@ white-space: nowrap; word-wrap: normal; direction: ltr; + -webkit-font-feature-settings: 'liga'; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; - -webkit-font-feature-settings: "liga"1; - -moz-font-feature-settings: "liga"1; - font-feature-settings: "liga"1; + font-feature-settings: "liga" 1; line-height: 1; overflow: hidden; - vertical-align: middle -} \ No newline at end of file + vertical-align: middle; +} diff --git a/src/bower_components/emby-webcomponents/formdialog.css b/src/bower_components/emby-webcomponents/formdialog.css index d44a7ed871..b976d8130e 100644 --- a/src/bower_components/emby-webcomponents/formdialog.css +++ b/src/bower_components/emby-webcomponents/formdialog.css @@ -1,145 +1,115 @@ -.formDialog, -.formDialogHeader { - display: -webkit-box; - display: -webkit-flex -} - -.formDialog, -.formDialogFooter-vertical { - -webkit-box-orient: vertical; - -webkit-box-direction: normal -} - .formDialog { display: flex; - -webkit-flex-direction: column; flex-direction: column; - position: relative + position: relative; } .formDialogHeader { padding: 1em .5em; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } .formDialogHeaderTitle { margin-left: .25em; + /* In case of h1, h2, h3 */ margin-top: 0; - margin-bottom: 0 + margin-bottom: 0; } .formDialogContent:not(.no-grow) { - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - flex-grow: 1 + flex-grow: 1; } .dialogContentInner { - padding: .5em 1em 20em + padding: .5em 1em 20em 1em; } .dialogContentInner-mini { - padding-bottom: 10em + padding-bottom: 10em; } .dialog-content-centered { margin: 0 auto; - max-width: 53em + max-width: 53em; } .dialogContentTitle { - margin-top: 1em + margin-top: 1em; } .formDialogFooter { bottom: 0; left: 0; right: 0; - display: -webkit-box; - display: -webkit-flex; display: flex; position: absolute; padding: 1.25em 1em; + /* Without this emby-checkbox is able to appear on top */ z-index: 1; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; - -webkit-flex-wrap: wrap; - flex-wrap: wrap + flex-wrap: wrap; } .formDialogFooter-flex { position: static; - width: 100% + width: 100%; } .formDialogFooter-vertical { padding-bottom: 1.5em; - -webkit-flex-direction: column; flex-direction: column; width: 80% !important; - padding-top: .5em + padding-top: .5em; } .formDialogFooterItem { margin: .5em !important; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; flex-grow: 1; text-align: center; - -webkit-flex-basis: 0; - flex-basis: 0 + flex-basis: 0; } .formDialogFooterItem-vertical { max-width: none !important; width: 100%; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; - margin: 1em !important + margin: 1em !important; } .formDialogFooterItem-nomarginbottom { - margin-bottom: 0 !important + margin-bottom: 0 !important; } .formDialogFooterItem-autosize { - -webkit-flex-basis: initial; flex-basis: initial; - -webkit-box-flex: initial; - -webkit-flex-grow: initial; flex-grow: initial; padding-left: 2em; - padding-right: 2em + padding-right: 2em; } -@media all and (min-width:50em) { +@media all and (min-width: 50em) { + .formDialogFooterItem { - max-width: 80% + max-width: 80%; } .dialogContentInner { padding-left: 1.5em; - padding-right: 1.5em + padding-right: 1.5em; } } -@media all and (min-width:80em) { +@media all and (min-width: 80em) { + .formDialogFooterItem { - max-width: 70% + max-width: 70%; } .dialogContentInner { padding-left: 2em; - padding-right: 2em + padding-right: 2em; } -} \ No newline at end of file +} diff --git a/src/bower_components/emby-webcomponents/fullscreen/fullscreen-dc.js b/src/bower_components/emby-webcomponents/fullscreen/fullscreen-dc.js index a7f6ff1e13..bc12a6a76d 100644 --- a/src/bower_components/emby-webcomponents/fullscreen/fullscreen-dc.js +++ b/src/bower_components/emby-webcomponents/fullscreen/fullscreen-dc.js @@ -1,12 +1,26 @@ -define(["dom", "fullscreenManager"], function(dom, fullscreenManager) { - "use strict"; +define(['dom', 'fullscreenManager'], function (dom, fullscreenManager) { + 'use strict'; function isTargetValid(target) { - return !dom.parentWithTag(target, ["BUTTON", "INPUT", "TEXTAREA"]) + + if (dom.parentWithTag(target, ['BUTTON', 'INPUT', 'TEXTAREA'])) { + return false; + } + + return true; } - dom.addEventListener(window, "dblclick", function(e) { - isTargetValid(e.target) && (fullscreenManager.isFullScreen() ? fullscreenManager.exitFullscreen() : fullscreenManager.requestFullscreen()) + + dom.addEventListener(window, 'dblclick', function (e) { + + if (isTargetValid(e.target)) { + if (fullscreenManager.isFullScreen()) { + fullscreenManager.exitFullscreen(); + } else { + fullscreenManager.requestFullscreen(); + } + } + }, { - passive: !0 - }) + passive: true + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/fullscreen/fullscreenmanager.js b/src/bower_components/emby-webcomponents/fullscreen/fullscreenmanager.js index adfee87460..d39d8fd3b6 100644 --- a/src/bower_components/emby-webcomponents/fullscreen/fullscreenmanager.js +++ b/src/bower_components/emby-webcomponents/fullscreen/fullscreenmanager.js @@ -1,24 +1,74 @@ -define(["events", "dom"], function(events, dom) { - "use strict"; +define(['events', 'dom'], function (events, dom) { + 'use strict'; - function fullscreenManager() {} + function fullscreenManager() { + + } + + fullscreenManager.prototype.requestFullscreen = function (element) { + + element = element || document.documentElement; + + if (element.requestFullscreen) { + element.requestFullscreen(); + return; + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen(); + return; + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + return; + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen(); + return; + } + + // Hack - This is only available for video elements in ios safari + if (element.tagName !== 'VIDEO') { + element = document.querySelector('video') || element; + } + if (element.webkitEnterFullscreen) { + element.webkitEnterFullscreen(); + } + }; + + fullscreenManager.prototype.exitFullscreen = function () { + + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } else if (document.webkitCancelFullscreen) { + document.webkitCancelFullscreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } + }; + + fullscreenManager.prototype.isFullScreen = function () { + + return document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement ? true : false; + }; + + var manager = new fullscreenManager(); function onFullScreenChange() { - events.trigger(manager, "fullscreenchange") + events.trigger(manager, 'fullscreenchange'); } - fullscreenManager.prototype.requestFullscreen = function(element) { - return element = element || document.documentElement, element.requestFullscreen ? void element.requestFullscreen() : element.mozRequestFullScreen ? void element.mozRequestFullScreen() : element.webkitRequestFullscreen ? void element.webkitRequestFullscreen() : element.msRequestFullscreen ? void element.msRequestFullscreen() : ("VIDEO" !== element.tagName && (element = document.querySelector("video") || element), void(element.webkitEnterFullscreen && element.webkitEnterFullscreen())) - }, fullscreenManager.prototype.exitFullscreen = function() { - document.exitFullscreen ? document.exitFullscreen() : document.mozCancelFullScreen ? document.mozCancelFullScreen() : document.webkitExitFullscreen ? document.webkitExitFullscreen() : document.webkitCancelFullscreen ? document.webkitCancelFullscreen() : document.msExitFullscreen && document.msExitFullscreen() - }, fullscreenManager.prototype.isFullScreen = function() { - return !!(document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement) - }; - var manager = new fullscreenManager; - return dom.addEventListener(document, "fullscreenchange", onFullScreenChange, { - passive: !0 - }), dom.addEventListener(document, "webkitfullscreenchange", onFullScreenChange, { - passive: !0 - }), dom.addEventListener(document, "mozfullscreenchange", onFullScreenChange, { - passive: !0 - }), manager + + dom.addEventListener(document, 'fullscreenchange', onFullScreenChange, { + passive: true + }); + + dom.addEventListener(document, 'webkitfullscreenchange', onFullScreenChange, { + passive: true + }); + + dom.addEventListener(document, 'mozfullscreenchange', onFullScreenChange, { + passive: true + }); + + return manager; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/globalize.js b/src/bower_components/emby-webcomponents/globalize.js index 0390860404..c36dea1910 100644 --- a/src/bower_components/emby-webcomponents/globalize.js +++ b/src/bower_components/emby-webcomponents/globalize.js @@ -1,127 +1,287 @@ -define(["connectionManager", "userSettings", "events"], function(connectionManager, userSettings, events) { - "use strict"; +define(['connectionManager', 'userSettings', 'events'], function (connectionManager, userSettings, events) { + 'use strict'; + + var allTranslations = {}; + var currentCulture; + var currentDateTimeCulture; function getCurrentLocale() { - return currentCulture + + return currentCulture; } function getCurrentDateTimeLocale() { - return currentDateTimeCulture + return currentDateTimeCulture; } function getDefaultLanguage() { - var culture = document.documentElement.getAttribute("data-culture"); - return culture || (navigator.language ? navigator.language : navigator.userLanguage ? navigator.userLanguage : navigator.languages && navigator.languages.length ? navigator.languages[0] : "en-us") + + var culture = document.documentElement.getAttribute('data-culture'); + + if (culture) { + return culture; + } + + if (navigator.language) { + return navigator.language; + } + if (navigator.userLanguage) { + return navigator.userLanguage; + } + if (navigator.languages && navigator.languages.length) { + return navigator.languages[0]; + } + + return 'en-us'; } function updateCurrentCulture() { + var culture; try { - culture = userSettings.language() - } catch (err) {} - culture = culture || getDefaultLanguage(), currentCulture = normalizeLocaleName(culture); + culture = userSettings.language(); + } catch (err) { + + } + culture = culture || getDefaultLanguage(); + + currentCulture = normalizeLocaleName(culture); + var dateTimeCulture; try { - dateTimeCulture = userSettings.dateTimeLocale() - } catch (err) {} - currentDateTimeCulture = dateTimeCulture ? normalizeLocaleName(dateTimeCulture) : currentCulture, ensureTranslations(currentCulture) + dateTimeCulture = userSettings.dateTimeLocale(); + } catch (err) { + + } + + if (dateTimeCulture) { + currentDateTimeCulture = normalizeLocaleName(dateTimeCulture); + } + else { + currentDateTimeCulture = currentCulture; + } + + ensureTranslations(currentCulture); } function ensureTranslations(culture) { - for (var i in allTranslations) ensureTranslation(allTranslations[i], culture) - } - function ensureTranslation(translationInfo, culture) { - return translationInfo.dictionaries[culture] ? Promise.resolve() : loadTranslation(translationInfo.translations, culture).then(function(dictionary) { - translationInfo.dictionaries[culture] = dictionary - }) - } - - function normalizeLocaleName(culture) { - culture = culture.replace("_", "-"); - var parts = culture.split("-"); - 2 === parts.length && parts[0].toLowerCase() === parts[1].toLowerCase() && (culture = parts[0].toLowerCase()); - var lower = culture.toLowerCase(); - return "ca-es" === lower ? "ca" : "sv-se" === lower ? "sv" : lower - } - - function getDictionary(module) { - module || (module = defaultModule()); - var translations = allTranslations[module]; - return translations ? translations.dictionaries[getCurrentLocale()] : {} - } - - function register(options) { - allTranslations[options.name] = { - translations: options.strings || options.translations, - dictionaries: {} + for (var i in allTranslations) { + ensureTranslation(allTranslations[i], culture); } } - function loadStrings(options) { - var locale = getCurrentLocale(); - return "string" == typeof options ? ensureTranslation(allTranslations[options], locale) : (register(options), ensureTranslation(allTranslations[options.name], locale)) + function ensureTranslation(translationInfo, culture) { + + if (translationInfo.dictionaries[culture]) { + return Promise.resolve(); + } + + return loadTranslation(translationInfo.translations, culture).then(function (dictionary) { + + translationInfo.dictionaries[culture] = dictionary; + }); } + function normalizeLocaleName(culture) { + + culture = culture.replace('_', '-'); + + // If it's de-DE, convert to just de + var parts = culture.split('-'); + if (parts.length === 2) { + if (parts[0].toLowerCase() === parts[1].toLowerCase()) { + culture = parts[0].toLowerCase(); + } + } + + var lower = culture.toLowerCase(); + + if (lower === 'ca-es') { + return 'ca'; + } + + // normalize Swedish + if (lower === 'sv-se') { + return 'sv'; + } + + return lower; + } + + function getDictionary(module) { + + if (!module) { + module = defaultModule(); + } + + var translations = allTranslations[module]; + + if (!translations) { + return {}; + } + + return translations.dictionaries[getCurrentLocale()]; + } + + function register(options) { + + allTranslations[options.name] = { + translations: options.strings || options.translations, + dictionaries: {} + }; + } + + function loadStrings(options) { + + var locale = getCurrentLocale(); + + if (typeof options === 'string') { + return ensureTranslation(allTranslations[options], locale); + } else { + register(options); + return ensureTranslation(allTranslations[options.name], locale); + } + } + + var cacheParam = new Date().getTime(); function loadTranslation(translations, lang) { + lang = normalizeLocaleName(lang); - var filtered = translations.filter(function(t) { - return normalizeLocaleName(t.lang) === lang + + var filtered = translations.filter(function (t) { + return normalizeLocaleName(t.lang) === lang; }); - return filtered.length || (filtered = translations.filter(function(t) { - return "en-us" === normalizeLocaleName(t.lang) - })), new Promise(function(resolve, reject) { - if (!filtered.length) return void resolve(); + + if (!filtered.length) { + filtered = translations.filter(function (t) { + return normalizeLocaleName(t.lang) === 'en-us'; + }); + } + + return new Promise(function (resolve, reject) { + + if (!filtered.length) { + resolve(); + return; + } + var url = filtered[0].path; - url += -1 === url.indexOf("?") ? "?" : "&", url += "v=" + cacheParam; - var xhr = new XMLHttpRequest; - xhr.open("GET", url, !0), xhr.onload = function(e) { - resolve(this.status < 400 ? JSON.parse(this.response) : {}) - }, xhr.onerror = function() { - resolve({}) - }, xhr.send() - }) + + url += url.indexOf('?') === -1 ? '?' : '&'; + url += 'v=' + cacheParam; + + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + + xhr.onload = function (e) { + if (this.status < 400) { + resolve(JSON.parse(this.response)); + } else { + resolve({}); + } + }; + + xhr.onerror = function () { + resolve({}); + }; + xhr.send(); + }); } function translateKey(key) { - var module, parts = key.split("#"); - return parts.length > 1 && (module = parts[0], key = parts[1]), translateKeyFromModule(key, module) + + var parts = key.split('#'); + var module; + + if (parts.length > 1) { + module = parts[0]; + key = parts[1]; + } + + return translateKeyFromModule(key, module); } function translateKeyFromModule(key, module) { + var dictionary = getDictionary(module); - return dictionary ? dictionary[key] || key : key + + if (!dictionary) { + return key; + } + + return dictionary[key] || key; } function replaceAll(str, find, replace) { - return str.split(find).join(replace) + + return str.split(find).join(replace); } function translate(key) { - for (var val = translateKey(key), i = 1; i < arguments.length; i++) val = replaceAll(val, "{" + (i - 1) + "}", arguments[i]); - return val + + var val = translateKey(key); + + for (var i = 1; i < arguments.length; i++) { + + val = replaceAll(val, '{' + (i - 1) + '}', arguments[i]); + + } + + return val; } function translateHtml(html, module) { - if (module || (module = defaultModule()), !module) throw new Error("module cannot be null or empty"); - var startIndex = html.indexOf("${"); - if (-1 === startIndex) return html; + + if (!module) { + module = defaultModule(); + } + + if (!module) { + throw new Error('module cannot be null or empty'); + } + + var startIndex = html.indexOf('${'); + + if (startIndex === -1) { + return html; + } + startIndex += 2; - var endIndex = html.indexOf("}", startIndex); - if (-1 === endIndex) return html; - var key = html.substring(startIndex, endIndex), - val = translateKeyFromModule(key, module); - return html = html.replace("${" + key + "}", val), translateHtml(html, module) + var endIndex = html.indexOf('}', startIndex); + + if (endIndex === -1) { + return html; + } + + var key = html.substring(startIndex, endIndex); + var val = translateKeyFromModule(key, module); + + html = html.replace('${' + key + '}', val); + return translateHtml(html, module); } + var _defaultModule; function defaultModule(val) { - return val && (_defaultModule = val), _defaultModule + + if (val) { + + _defaultModule = val; + } + + return _defaultModule; } - var currentCulture, currentDateTimeCulture, _defaultModule, allTranslations = {}, - cacheParam = (new Date).getTime(); - return updateCurrentCulture(), events.on(connectionManager, "localusersignedin", updateCurrentCulture), events.on(userSettings, "change", function(e, name) { - "language" !== name && "datetimelocale" !== name || updateCurrentCulture() - }), { + + updateCurrentCulture(); + + events.on(connectionManager, 'localusersignedin', updateCurrentCulture); + events.on(userSettings, 'change', function (e, name) { + if (name === 'language' || name === 'datetimelocale') { + updateCurrentCulture(); + } + }); + + return { getString: translate, translate: translate, translateDocument: translateHtml, @@ -131,5 +291,5 @@ define(["connectionManager", "userSettings", "events"], function(connectionManag getCurrentLocale: getCurrentLocale, getCurrentDateTimeLocale: getCurrentDateTimeLocale, register: register - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/guide/guide-settings.js b/src/bower_components/emby-webcomponents/guide/guide-settings.js index 624a582574..e95d750c9a 100644 --- a/src/bower_components/emby-webcomponents/guide/guide-settings.js +++ b/src/bower_components/emby-webcomponents/guide/guide-settings.js @@ -1,71 +1,172 @@ -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"; +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) { - for (var categories = [], chkCategorys = context.querySelectorAll(".chkCategory"), i = 0, length = chkCategorys.length; i < length; i++) { - var type = chkCategorys[i].getAttribute("data-type"); - chkCategorys[i].checked && categories.push(type) + + 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); + } } - categories.length >= 4 && categories.push("series"), categories.push("all"), options.categories = categories + + if (categories.length >= 4) { + categories.push('series'); + } + + // differentiate between none and all + categories.push('all'); + options.categories = categories; } function loadCategories(context, options) { - for (var selectedCategories = options.categories || [], chkCategorys = context.querySelectorAll(".chkCategory"), i = 0, length = chkCategorys.length; i < length; i++) { - var type = chkCategorys[i].getAttribute("data-type"); - chkCategorys[i].checked = !selectedCategories.length || -1 !== selectedCategories.indexOf(type) + + 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, chkIndicators = context.querySelectorAll(".chkIndicator"); + + var i, length; + + var chkIndicators = context.querySelectorAll('.chkIndicator'); for (i = 0, length = chkIndicators.length; i < length; i++) { - var type = chkIndicators[i].getAttribute("data-type"); - userSettings.set("guide-indicator-" + type, chkIndicators[i].checked) + + var type = chkIndicators[i].getAttribute('data-type'); + userSettings.set('guide-indicator-' + type, chkIndicators[i].checked); } - userSettings.set("guide-colorcodedbackgrounds", context.querySelector(".chkColorCodedBackgrounds").checked), userSettings.set("livetv-favoritechannelsattop", context.querySelector(".chkFavoriteChannelsAtTop").checked); - var sortBys = context.querySelectorAll(".chkSortOrder"); - for (i = 0, length = sortBys.length; i < length; i++) + + userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked); + userSettings.set('livetv-favoritechannelsattop', context.querySelector('.chkFavoriteChannelsAtTop').checked); + + var sortBys = context.querySelectorAll('.chkSortOrder'); + for (i = 0, length = sortBys.length; i < length; i++) { if (sortBys[i].checked) { - userSettings.set("livetv-channelorder", sortBys[i].value); - break + userSettings.set('livetv-channelorder', sortBys[i].value); + break; } + } } function load(context) { - var i, length, chkIndicators = context.querySelectorAll(".chkIndicator"); + + var i, length; + + var chkIndicators = context.querySelectorAll('.chkIndicator'); for (i = 0, length = chkIndicators.length; i < length; i++) { - var type = chkIndicators[i].getAttribute("data-type"); - "true" === chkIndicators[i].getAttribute("data-default") ? chkIndicators[i].checked = "false" !== userSettings.get("guide-indicator-" + type) : chkIndicators[i].checked = "true" === userSettings.get("guide-indicator-" + type) + + var type = chkIndicators[i].getAttribute('data-type'); + + if (chkIndicators[i].getAttribute('data-default') === 'true') { + chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) !== 'false'; + } else { + chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) === 'true'; + } + } + + context.querySelector('.chkColorCodedBackgrounds').checked = userSettings.get('guide-colorcodedbackgrounds') === 'true'; + context.querySelector('.chkFavoriteChannelsAtTop').checked = userSettings.get('livetv-favoritechannelsattop') !== 'false'; + + var sortByValue = userSettings.get('livetv-channelorder') || 'Number'; + + var sortBys = context.querySelectorAll('.chkSortOrder'); + for (i = 0, length = sortBys.length; i < length; i++) { + sortBys[i].checked = sortBys[i].value === sortByValue; + } + } + + function onSortByChange() { + var newValue = this.value; + if (this.checked) { + var changed = options.query.SortBy !== newValue; + + options.query.SortBy = newValue.replace('_', ','); + options.query.StartIndex = 0; + + if (options.callback && changed) { + options.callback(); + } } - context.querySelector(".chkColorCodedBackgrounds").checked = "true" === userSettings.get("guide-colorcodedbackgrounds"), context.querySelector(".chkFavoriteChannelsAtTop").checked = "false" !== userSettings.get("livetv-favoritechannelsattop"); - var sortByValue = userSettings.get("livetv-channelorder") || "Number", - sortBys = context.querySelectorAll(".chkSortOrder"); - for (i = 0, length = sortBys.length; i < length; i++) sortBys[i].checked = sortBys[i].value === sortByValue } function showEditor(options) { - return new Promise(function(resolve, reject) { - var settingsChanged = !1; - require(["text!./guide-settings.template.html"], function(template) { + + return new Promise(function (resolve, reject) { + + var settingsChanged = false; + + require(['text!./guide-settings.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + 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 = !0 - }), dlg.addEventListener("close", function() { - layoutManager.tv && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), save(dlg), saveCategories(dlg, options), settingsChanged ? resolve() : reject() - }), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), layoutManager.tv && scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1), load(dlg), loadCategories(dlg, options), dialogHelper.open(dlg) - }) - }) + + 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); + saveCategories(dlg, options); + + if (settingsChanged) { + resolve(); + } else { + reject(); + } + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + dialogHelper.close(dlg); + }); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); + } + + load(dlg); + loadCategories(dlg, options); + dialogHelper.open(dlg); + }); + }); } + return { show: showEditor - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/guide/guide.css b/src/bower_components/emby-webcomponents/guide/guide.css index fa1d4f0204..fcac17f272 100644 --- a/src/bower_components/emby-webcomponents/guide/guide.css +++ b/src/bower_components/emby-webcomponents/guide/guide.css @@ -1,194 +1,141 @@ -.tvGuideHeader, -.tvguide { - display: -webkit-box; - display: -webkit-flex -} - -.channelPrograms, -.programContainer, -.timeslotHeadersInner, -.tvProgram { - position: relative -} - -.channelPrograms, -.channelsContainer, -.tvGuideHeader, -.tvguide { - -webkit-box-orient: vertical; - -webkit-box-direction: normal -} - -.guideChannelName, -.guideChannelNumber, -.guideProgramName, -.guideProgramNameText { - -o-text-overflow: ellipsis -} - .tvguide { display: flex; - -webkit-flex-direction: column; flex-direction: column; - -webkit-box-align: initial; - -webkit-align-items: initial; - align-items: initial + align-items: initial; } .tvGuideHeader { white-space: nowrap; width: 100%; - -webkit-flex-direction: column; flex-direction: column; - -webkit-flex-shrink: 0; flex-shrink: 0; display: flex; - contain: layout style paint + contain: layout style paint; } .layout-desktop .tvGuideHeader { - margin-bottom: .5em + margin-bottom: .5em; } .guideHeaderDateSelection { font-size: 86%; - padding: .4em 0 + padding: .4em 0; } .guide-headerTimeslots { - display: -webkit-box; - display: -webkit-flex; - display: flex + display: flex; } .tvProgramSectionHeader { - margin: 0 + margin: 0; } .tvProgram { display: block; text-decoration: none; - white-space: nowrap + white-space: nowrap; + position: relative; } .guideProgramIndicator { text-transform: uppercase; - -webkit-border-radius: .25em; border-radius: .25em; margin-right: .5em; font-size: 82%; padding: .2em .25em; - display: -webkit-inline-box; - display: -webkit-inline-flex; display: inline-flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; text-align: center; - margin-left: 1em + margin-left: 1em; } .guide-channelTimeslotHeader { - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center + flex-shrink: 0; + justify-content: center; } .timeslotHeaders { white-space: nowrap; font-weight: 500; - font-size: 120% + font-size: 120%; } .programContainer { white-space: nowrap; - -webkit-box-align: start; - -webkit-align-items: flex-start; + position: relative; align-items: flex-start; - contain: strict + contain: strict; +} + +.channelPrograms { + white-space: nowrap; + position: relative; + contain: strict; + box-sizing: border-box; +} + +.timeslotHeadersInner { + position: relative; } .guideSpacer { width: .3em; - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } -.channelPrograms, -.timeslotHeadersInner { - width: 1800vw +.channelPrograms, .timeslotHeadersInner { + width: 1800vw; } -@media all and (min-width:37.5em) { +@media all and (min-width: 37.5em) { - .channelPrograms, - .timeslotHeadersInner { - width: 1400vw + .channelPrograms, .timeslotHeadersInner { + width: 1400vw; } } -@media all and (min-width:50em) { +@media all and (min-width: 50em) { - .channelPrograms, - .timeslotHeadersInner { - width: 1200vw + .channelPrograms, .timeslotHeadersInner { + width: 1200vw; } } -@media all and (min-width:80em) { +@media all and (min-width: 80em) { - .channelPrograms, - .timeslotHeadersInner { - width: 810vw + .channelPrograms, .timeslotHeadersInner { + width: 810vw; } } .timeslotHeader { - display: -webkit-inline-box; - display: -webkit-inline-flex; display: inline-flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; text-indent: .25em; - width: 2.0833333333333333333333333333333% + width: 2.0833333333333333333333333333333%; } -.guide-channelHeaderCell, -.guide-channelTimeslotHeader, -.programCell { - color: inherit; +.guide-channelHeaderCell, .guide-channelTimeslotHeader { + padding: 0 !important; cursor: pointer; + outline: none !important; + width: 100%; vertical-align: middle; font-family: inherit; - text-decoration: none; - -webkit-box-align: center; - text-align: left; - overflow: hidden -} - -.guide-channelHeaderCell, -.guide-channelTimeslotHeader { - padding: 0 !important; - outline: 0 !important; - width: 100%; font-size: inherit; - -o-text-overflow: ellipsis; + overflow: hidden; text-overflow: ellipsis; margin: 0 1px 0 0; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-align-items: center; align-items: center; + text-decoration: none; + /* Needed in firefox */ + text-align: left; contain: strict; - -webkit-flex-shrink: 0; flex-shrink: 0; - -webkit-border-radius: .12em; - border-radius: .12em + border-radius: .12em; + color: inherit; } .guide-channelHeaderCell { @@ -198,187 +145,151 @@ height: 4.42em; contain: strict; position: relative; - background: 0 0 + background: transparent; } .guide-channelTimeslotHeader { border: 0 !important; - border-right-color: transparent } -.channelsContainer, -.guide-channelTimeslotHeader { - width: 24vw +/* Important - have to put the fixed width on channelsContainer, not the individual channelHeaderCell + This was causing channelsContainer to extend beyond the fixed width on ps4, tizen, lg and opera tv. +*/ +.channelsContainer, .guide-channelTimeslotHeader { + width: 24vw; } @media all and (min-width:31.25em) { - - .channelsContainer, - .guide-channelTimeslotHeader { - width: 16vw + .channelsContainer, .guide-channelTimeslotHeader { + width: 16vw; } } @media all and (min-width:37.5em) { - - .channelsContainer, - .guide-channelTimeslotHeader { - width: 16vw + .channelsContainer, .guide-channelTimeslotHeader { + width: 16vw; } } @media all and (min-width:50em) { - - .channelsContainer, - .guide-channelTimeslotHeader { - width: 14vw + .channelsContainer, .guide-channelTimeslotHeader { + width: 14vw; } } @media all and (min-width:80em) { - - .channelsContainer, - .guide-channelTimeslotHeader { - width: 12vw + .channelsContainer, .guide-channelTimeslotHeader { + width: 12vw; } } .btnGuideViewSettings { margin: 0; - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } .btnGuideViewSettingsIcon { - font-size: 1.5em !important + font-size: 1.5em !important; } .selectDateIcon { - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } -@media all and (max-width:50em) { +@media all and (max-width: 50em) { - .guideHdIcon, - .liveTvProgram, - .newTvProgram, - .premiereTvProgram { - display: none + .newTvProgram, .liveTvProgram, .premiereTvProgram, .guideHdIcon { + display: none; } } -.channelPrograms, -.programCell { - border-style: solid; - display: -webkit-box; - display: -webkit-flex; - contain: strict -} - .channelPrograms { - white-space: nowrap; - -webkit-box-sizing: border-box; - box-sizing: border-box; height: 4.42em; + contain: strict; display: flex; - -webkit-flex-direction: column; flex-direction: column; - border-width: 1px 0 + border-style: solid; + border-width: 1px 0 1px 0; } -.channelPrograms+.channelPrograms, -.guide-channelHeaderCell+.guide-channelHeaderCell { - margin-top: -1px + .channelPrograms + .channelPrograms, .guide-channelHeaderCell + .guide-channelHeaderCell { + margin-top: -1px; + } + +.channelPrograms-tv, .guide-channelHeaderCell-tv { + height: 3em; } -.channelPrograms-tv, -.guide-channelHeaderCell-tv { - height: 3em +.guide-channelTimeslotHeader { + border-right-color: transparent; } -.guide-channelTimeslotHeader, -.timeslotHeader { - background: 0 0 !important; - height: 2.8em +.guide-channelTimeslotHeader, .timeslotHeader { + background: transparent !important; + height: 2.8em; } .programGrid { padding-bottom: 4px; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - flex-grow: 1 + flex-grow: 1; } .programCell { - background: 0 0; + color: inherit; + background: transparent; + border-style: solid; border-width: 0 0 0 1px; padding: 0 !important; + cursor: pointer; + outline: none !important; width: 100%; + vertical-align: middle; + font-family: inherit; font-size: inherit; position: absolute; top: 0; bottom: 0; display: flex; - -webkit-align-items: center; + text-decoration: none; + overflow: hidden; align-items: center; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; + /* Needed for Firefox */ + text-align: left; + contain: strict; flex-grow: 1; - margin: 0 !important -} - -.channelsContainer, -.guideProgramName, -.programGrid { - contain: layout style paint -} - -.guide-programNameCaret, -.guideProgramName { - display: -webkit-box; - display: -webkit-flex; - -webkit-box-align: center + margin: 0 !important; } .guideProgramName { - padding: 0 .7em; + padding: 0 .7em 0; overflow: hidden; text-overflow: ellipsis; - -webkit-align-items: center; align-items: center; display: flex; position: relative; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - flex-grow: 1 + flex-grow: 1; + contain: layout style paint; + /*transition: transform 60ms ease-out;*/ } .guide-programNameCaret { display: flex; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; - font-size: 200% + font-size: 200%; } .guideProgramNameText { margin: 0; - font-weight: 400; + font-weight: normal; overflow: hidden; - text-overflow: ellipsis + text-overflow: ellipsis; } .guideProgramSecondaryInfo { - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - margin-top: .1em + margin-top: .1em; } .programIcon { @@ -387,26 +298,22 @@ width: 1em; font-size: 1.6em; color: #ddd; - -webkit-flex-shrink: 0; flex-shrink: 0; - -webkit-box-flex: 0; - -webkit-flex-grow: 0; - flex-grow: 0 + flex-grow: 0; } .guide-programTextIcon { - font-weight: 700; + font-weight: bold; font-size: .9em; padding: .16em .3em; - -webkit-border-radius: .25em; border-radius: .25em; margin-right: .35em; width: auto; - height: auto + height: auto; } .guide-programTextIcon-tv { - font-size: .74em + font-size: .74em; } .guideChannelNumber { @@ -414,8 +321,8 @@ max-width: 30%; text-overflow: ellipsis; overflow: hidden; - font-weight: 400; - margin: 0 + font-weight: normal; + margin: 0; } .guideChannelName { @@ -423,7 +330,7 @@ margin-right: 1em; text-overflow: ellipsis; overflow: hidden; - max-width: 70% + max-width: 70%; } .guideChannelImage { @@ -432,68 +339,62 @@ top: 15%; bottom: 15%; width: 40%; - -webkit-background-size: contain; background-size: contain; background-repeat: no-repeat; - background-position: right center + background-position: right center; } -@media all and (min-width:62.5em) { +@media all and (min-width: 62.5em) { + .guideChannelName { - max-width: 40% + max-width: 40%; } } -@media all and (max-width:62.5em) { +@media all and (max-width: 62.5em) { + .guideChannelNumber { - display: none + display: none; } .guideChannelImage { - width: 70% + width: 70%; } } .channelsContainer { - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-flex-shrink: 0; flex-shrink: 0; - -webkit-flex-direction: column; - flex-direction: column + flex-direction: column; } -.guide-channelHeaderCell, -.programCell { - outline: 0 !important +.channelsContainer, .programGrid { + contain: layout style paint; } -.seriesTimerIcon, -.timerIcon { - color: #c33 !important +.programCell, .guide-channelHeaderCell { + outline: none !important; +} + +.timerIcon, .seriesTimerIcon { + color: #cc3333 !important; } .seriesTimerIcon-inactive { color: inherit !important; - opacity: .7 + opacity: .7; } .guideOptions { - -webkit-flex-shrink: 0; flex-shrink: 0; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; - align-items: center + align-items: center; } -@media all and (max-width:50em), -all and (max-height:37.5em) { +@media all and (max-width: 50em), all and (max-height: 37.5em) { + .tvGuideHeader { - padding-left: 0 + padding-left: 0; } } @@ -501,31 +402,29 @@ all and (max-height:37.5em) { margin: 1em auto; text-align: center; padding: 1em; - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } .noRubberBanding { - padding-bottom: 7em + /* This is needed to combat the rubber banding in iOS */ + padding-bottom: 7em; } .guideDateTabsSlider { - text-align: center + text-align: center; } .guide-date-tab-button { padding: .3em .7em !important; margin: 0 .3em !important; - font-weight: 400 + font-weight: normal; } -.guide-date-tab-button.emby-tab-button-active { - border-color: transparent !important -} + .guide-date-tab-button.emby-tab-button-active { + border-color: transparent !important; + } -.guide-date-tab-button.emby-button-tv:focus { - -webkit-border-radius: .15em !important; - border-radius: .15em !important; - -webkit-transform: none !important; - transform: none !important -} \ No newline at end of file + .guide-date-tab-button.emby-button-tv:focus { + border-radius: .15em !important; + transform: none !important; + } diff --git a/src/bower_components/emby-webcomponents/guide/guide.js b/src/bower_components/emby-webcomponents/guide/guide.js index 87fcaf8218..0924339ff2 100644 --- a/src/bower_components/emby-webcomponents/guide/guide.js +++ b/src/bower_components/emby-webcomponents/guide/guide.js @@ -1,517 +1,1290 @@ -define(["require", "inputManager", "browser", "globalize", "connectionManager", "scrollHelper", "serverNotifications", "loading", "datetime", "focusManager", "playbackManager", "userSettings", "imageLoader", "events", "layoutManager", "itemShortcuts", "dom", "css!./guide.css", "programStyles", "material-icons", "scrollStyles", "emby-button", "paper-icon-button-light", "emby-tabs", "emby-scroller", "flexStyles", "registerElement"], function(require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) { - "use strict"; +define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', 'scrollHelper', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'playbackManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'dom', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-button', 'paper-icon-button-light', 'emby-tabs', 'emby-scroller', 'flexStyles', 'registerElement'], function (require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) { + 'use strict'; function showViewSettings(instance) { - require(["guide-settings-dialog"], function(guideSettingsDialog) { - guideSettingsDialog.show(instance.categoryOptions).then(function() { - instance.refresh() - }) - }) + + require(['guide-settings-dialog'], function (guideSettingsDialog) { + guideSettingsDialog.show(instance.categoryOptions).then(function () { + instance.refresh(); + }); + }); } function updateProgramCellOnScroll(cell, scrollPct) { + var left = cell.posLeft; - left || (left = parseFloat(cell.style.left.replace("%", "")), cell.posLeft = left); + if (!left) { + left = parseFloat(cell.style.left.replace('%', '')); + cell.posLeft = left; + } var width = cell.posWidth; - width || (width = parseFloat(cell.style.width.replace("%", "")), cell.posWidth = width); - var right = left + width, - newPct = Math.max(Math.min(scrollPct, right), left), - offset = newPct - left, - pctOfWidth = offset / width * 100, - guideProgramName = cell.guideProgramName; - guideProgramName || (guideProgramName = cell.querySelector(".guideProgramName"), cell.guideProgramName = guideProgramName); + if (!width) { + width = parseFloat(cell.style.width.replace('%', '')); + cell.posWidth = width; + } + + var right = left + width; + var newPct = Math.max(Math.min(scrollPct, right), left); + + var offset = newPct - left; + var pctOfWidth = (offset / width) * 100; + + //console.log(pctOfWidth); + var guideProgramName = cell.guideProgramName; + if (!guideProgramName) { + guideProgramName = cell.querySelector('.guideProgramName'); + cell.guideProgramName = guideProgramName; + } + var caret = cell.caret; - caret || (caret = cell.querySelector(".guide-programNameCaret"), cell.caret = caret), guideProgramName && (pctOfWidth > 0 && pctOfWidth <= 100 ? (guideProgramName.style.transform = "translateX(" + pctOfWidth + "%)", caret.classList.remove("hide")) : (guideProgramName.style.transform = "none", caret.classList.add("hide"))) + if (!caret) { + caret = cell.querySelector('.guide-programNameCaret'); + cell.caret = caret; + } + + if (guideProgramName) { + if (pctOfWidth > 0 && pctOfWidth <= 100) { + //guideProgramName.style.marginLeft = pctOfWidth + '%'; + guideProgramName.style.transform = 'translateX(' + pctOfWidth + '%)'; + caret.classList.remove('hide'); + } else { + //guideProgramName.style.marginLeft = '0'; + guideProgramName.style.transform = 'none'; + caret.classList.add('hide'); + } + } } + var isUpdatingProgramCellScroll = false; function updateProgramCellsOnScroll(programGrid, programCells) { - isUpdatingProgramCellScroll || (isUpdatingProgramCellScroll = !0, requestAnimationFrame(function() { - for (var scrollLeft = programGrid.scrollLeft, scrollPct = scrollLeft ? scrollLeft / programGrid.scrollWidth * 100 : 0, i = 0, length = programCells.length; i < length; i++) updateProgramCellOnScroll(programCells[i], scrollPct); - isUpdatingProgramCellScroll = !1 - })) + + if (isUpdatingProgramCellScroll) { + return; + } + + isUpdatingProgramCellScroll = true; + + requestAnimationFrame(function () { + + var scrollLeft = programGrid.scrollLeft; + + var scrollPct = scrollLeft ? (scrollLeft / programGrid.scrollWidth) * 100 : 0; + + for (var i = 0, length = programCells.length; i < length; i++) { + + updateProgramCellOnScroll(programCells[i], scrollPct); + } + + isUpdatingProgramCellScroll = false; + }); } function onProgramGridClick(e) { - if (layoutManager.tv) { - var programCell = dom.parentWithClass(e.target, "programCell"); - if (programCell) { - var startDate = programCell.getAttribute("data-startdate"), - endDate = programCell.getAttribute("data-enddate"); - startDate = datetime.parseISO8601Date(startDate, { - toLocal: !0 - }).getTime(), endDate = datetime.parseISO8601Date(endDate, { - toLocal: !0 - }).getTime(); - var now = (new Date).getTime(); - if (now >= startDate && now < endDate) { - var channelId = programCell.getAttribute("data-channelid"), - serverId = programCell.getAttribute("data-serverid"); - e.preventDefault(), e.stopPropagation(), playbackManager.play({ - ids: [channelId], - serverId: serverId - }) - } + + if (!layoutManager.tv) { + return; + } + + var programCell = dom.parentWithClass(e.target, 'programCell'); + if (programCell) { + + var startDate = programCell.getAttribute('data-startdate'); + var endDate = programCell.getAttribute('data-enddate'); + startDate = datetime.parseISO8601Date(startDate, { toLocal: true }).getTime(); + endDate = datetime.parseISO8601Date(endDate, { toLocal: true }).getTime(); + + var now = new Date().getTime(); + if (now >= startDate && now < endDate) { + + var channelId = programCell.getAttribute('data-channelid'); + var serverId = programCell.getAttribute('data-serverid'); + + e.preventDefault(); + e.stopPropagation(); + + playbackManager.play({ + ids: [channelId], + serverId: serverId + }); } } } function Guide(options) { - function restartAutoRefresh() { + + var self = this; + var items = {}; + + self.options = options; + self.categoryOptions = { categories: [] }; + + // 30 mins + var cellCurationMinutes = 30; + var cellDurationMs = cellCurationMinutes * 60 * 1000; + var msPerDay = 86400000; + var totalRendererdMs = msPerDay; + + var currentDate; + var currentStartIndex = 0; + var currentChannelLimit = 0; + var autoRefreshInterval; + var programCells; + var lastFocusDirection; + var programGrid; + + self.refresh = function () { + + currentDate = null; + reloadPage(options.element); + restartAutoRefresh(); + }; + + self.pause = function () { stopAutoRefresh(); - autoRefreshInterval = setInterval(function() { - self.refresh() - }, 9e5) + }; + + 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); + events.off(serverNotifications, 'SeriesTimerCancelled', onSeriesTimerCancelled); + + setScrollEvents(options.element, false); + itemShortcuts.off(options.element); + items = {}; + }; + + function restartAutoRefresh() { + + stopAutoRefresh(); + + var intervalMs = 60000 * 15; // (minutes) + + autoRefreshInterval = setInterval(function () { + self.refresh(); + }, intervalMs); } function stopAutoRefresh() { - autoRefreshInterval && (clearInterval(autoRefreshInterval), autoRefreshInterval = null) + if (autoRefreshInterval) { + clearInterval(autoRefreshInterval); + autoRefreshInterval = null; + } } function normalizeDateToTimeslot(date) { - return date.getMinutes() - cellCurationMinutes >= 0 ? date.setHours(date.getHours(), cellCurationMinutes, 0, 0) : date.setHours(date.getHours(), 0, 0, 0), date + + var minutesOffset = date.getMinutes() - cellCurationMinutes; + + if (minutesOffset >= 0) { + + date.setHours(date.getHours(), cellCurationMinutes, 0, 0); + + } else { + + date.setHours(date.getHours(), 0, 0, 0); + } + + return date; } function showLoading() { - loading.show() + loading.show(); } function hideLoading() { - loading.hide() + loading.hide(); } function reloadGuide(context, newStartDate, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) { - var apiClient = connectionManager.getApiClient(options.serverId), - channelQuery = { - StartIndex: 0, - EnableFavoriteSorting: "false" !== userSettings.get("livetv-favoritechannelsattop") - }; + + var apiClient = connectionManager.getApiClient(options.serverId); + + var channelQuery = { + + StartIndex: 0, + EnableFavoriteSorting: userSettings.get('livetv-favoritechannelsattop') !== 'false' + }; + channelQuery.UserId = apiClient.getCurrentUserId(); - currentChannelLimit = 500, showLoading(), channelQuery.StartIndex = currentStartIndex, channelQuery.Limit = 500, channelQuery.AddCurrentProgram = !1, channelQuery.EnableUserData = !1, channelQuery.EnableImageTypes = "Primary"; - var categories = self.categoryOptions.categories || [], - displayMovieContent = !categories.length || -1 !== categories.indexOf("movies"), - displaySportsContent = !categories.length || -1 !== categories.indexOf("sports"), - displayNewsContent = !categories.length || -1 !== categories.indexOf("news"), - displayKidsContent = !categories.length || -1 !== categories.indexOf("kids"), - displaySeriesContent = !categories.length || -1 !== categories.indexOf("series"); - displayMovieContent && displaySportsContent && displayNewsContent && displayKidsContent ? (channelQuery.IsMovie = null, channelQuery.IsSports = null, channelQuery.IsKids = null, channelQuery.IsNews = null, channelQuery.IsSeries = null) : (displayNewsContent && (channelQuery.IsNews = !0), displaySportsContent && (channelQuery.IsSports = !0), displayKidsContent && (channelQuery.IsKids = !0), displayMovieContent && (channelQuery.IsMovie = !0), displaySeriesContent && (channelQuery.IsSeries = !0)), "DatePlayed" === userSettings.get("livetv-channelorder") ? (channelQuery.SortBy = "DatePlayed", channelQuery.SortOrder = "Descending") : (channelQuery.SortBy = null, channelQuery.SortOrder = null); + + var channelLimit = 500; + currentChannelLimit = channelLimit; + + showLoading(); + + channelQuery.StartIndex = currentStartIndex; + channelQuery.Limit = channelLimit; + channelQuery.AddCurrentProgram = false; + channelQuery.EnableUserData = false; + channelQuery.EnableImageTypes = "Primary"; + + var categories = self.categoryOptions.categories || []; + var displayMovieContent = !categories.length || categories.indexOf('movies') !== -1; + var displaySportsContent = !categories.length || categories.indexOf('sports') !== -1; + var displayNewsContent = !categories.length || categories.indexOf('news') !== -1; + var displayKidsContent = !categories.length || categories.indexOf('kids') !== -1; + var displaySeriesContent = !categories.length || categories.indexOf('series') !== -1; + + if (displayMovieContent && displaySportsContent && displayNewsContent && displayKidsContent) { + channelQuery.IsMovie = null; + channelQuery.IsSports = null; + channelQuery.IsKids = null; + channelQuery.IsNews = null; + channelQuery.IsSeries = null; + } else { + if (displayNewsContent) { + channelQuery.IsNews = true; + } + if (displaySportsContent) { + channelQuery.IsSports = true; + } + if (displayKidsContent) { + channelQuery.IsKids = true; + } + if (displayMovieContent) { + channelQuery.IsMovie = true; + } + if (displaySeriesContent) { + channelQuery.IsSeries = true; + } + } + + if (userSettings.get('livetv-channelorder') === 'DatePlayed') { + channelQuery.SortBy = "DatePlayed"; + channelQuery.SortOrder = "Descending"; + } else { + channelQuery.SortBy = null; + channelQuery.SortOrder = null; + } + var date = newStartDate; - date = new Date(date.getTime() + 1e3); - var nextDay = new Date(date.getTime() + msPerDay - 2e3), - allowIndicators = dom.getWindowSize().innerWidth >= 600, - renderOptions = { - showHdIcon: allowIndicators && "true" === userSettings.get("guide-indicator-hd"), - showLiveIndicator: allowIndicators && "false" !== userSettings.get("guide-indicator-live"), - showPremiereIndicator: allowIndicators && "false" !== userSettings.get("guide-indicator-premiere"), - showNewIndicator: allowIndicators && "false" !== userSettings.get("guide-indicator-new"), - showRepeatIndicator: allowIndicators && "true" === userSettings.get("guide-indicator-repeat"), - showEpisodeTitle: !layoutManager.tv + // Add one second to avoid getting programs that are just ending + date = new Date(date.getTime() + 1000); + + // Subtract to avoid getting programs that are starting when the grid ends + var nextDay = new Date(date.getTime() + msPerDay - 2000); + + // Normally we'd want to just let responsive css handle this, + // but since mobile browsers are often underpowered, + // it can help performance to get them out of the markup + var allowIndicators = dom.getWindowSize().innerWidth >= 600; + + var renderOptions = { + showHdIcon: allowIndicators && userSettings.get('guide-indicator-hd') === 'true', + showLiveIndicator: allowIndicators && userSettings.get('guide-indicator-live') !== 'false', + showPremiereIndicator: allowIndicators && userSettings.get('guide-indicator-premiere') !== 'false', + showNewIndicator: allowIndicators && userSettings.get('guide-indicator-new') !== 'false', + showRepeatIndicator: allowIndicators && userSettings.get('guide-indicator-repeat') === 'true', + showEpisodeTitle: layoutManager.tv ? false : true + }; + + apiClient.getLiveTvChannels(channelQuery).then(function (channelsResult) { + + var btnPreviousPage = context.querySelector('.btnPreviousPage'); + var btnNextPage = context.querySelector('.btnNextPage'); + + if (channelsResult.TotalRecordCount > channelLimit) { + + context.querySelector('.guideOptions').classList.remove('hide'); + + btnPreviousPage.classList.remove('hide'); + btnNextPage.classList.remove('hide'); + + if (channelQuery.StartIndex) { + context.querySelector('.btnPreviousPage').disabled = false; + } else { + context.querySelector('.btnPreviousPage').disabled = true; + } + + if ((channelQuery.StartIndex + channelLimit) < channelsResult.TotalRecordCount) { + btnNextPage.disabled = false; + } else { + btnNextPage.disabled = true; + } + + } else { + context.querySelector('.guideOptions').classList.add('hide'); + } + + var programFields = []; + + var programQuery = { + UserId: apiClient.getCurrentUserId(), + MaxStartDate: nextDay.toISOString(), + MinEndDate: date.toISOString(), + channelIds: channelsResult.Items.map(function (c) { + return c.Id; + }).join(','), + ImageTypeLimit: 1, + EnableImages: false, + //EnableImageTypes: layoutManager.tv ? "Primary,Backdrop" : "Primary", + SortBy: "StartDate", + EnableTotalRecordCount: false, + EnableUserData: false }; - apiClient.getLiveTvChannels(channelQuery).then(function(channelsResult) { - var btnPreviousPage = context.querySelector(".btnPreviousPage"), - btnNextPage = context.querySelector(".btnNextPage"); - channelsResult.TotalRecordCount > 500 ? (context.querySelector(".guideOptions").classList.remove("hide"), btnPreviousPage.classList.remove("hide"), btnNextPage.classList.remove("hide"), channelQuery.StartIndex ? context.querySelector(".btnPreviousPage").disabled = !1 : context.querySelector(".btnPreviousPage").disabled = !0, channelQuery.StartIndex + 500 < channelsResult.TotalRecordCount ? btnNextPage.disabled = !1 : btnNextPage.disabled = !0) : context.querySelector(".guideOptions").classList.add("hide"); - var programFields = [], - programQuery = { - UserId: apiClient.getCurrentUserId(), - MaxStartDate: nextDay.toISOString(), - MinEndDate: date.toISOString(), - channelIds: channelsResult.Items.map(function(c) { - return c.Id - }).join(","), - ImageTypeLimit: 1, - EnableImages: !1, - SortBy: "StartDate", - EnableTotalRecordCount: !1, - EnableUserData: !1 - }; - renderOptions.showHdIcon && programFields.push("IsHD"), programFields.length && (programQuery.Fields = programFields.join("")), apiClient.getLiveTvPrograms(programQuery).then(function(programsResult) { - renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender), hideLoading() - }) - }) + + if (renderOptions.showHdIcon) { + programFields.push('IsHD'); + } + + if (programFields.length) { + programQuery.Fields = programFields.join(''); + } + + apiClient.getLiveTvPrograms(programQuery).then(function (programsResult) { + + renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender); + + hideLoading(); + + }); + }); } function getDisplayTime(date) { - if ("string" === (typeof date).toString().toLowerCase()) try { - date = datetime.parseISO8601Date(date, { - toLocal: !0 - }) - } catch (err) { - return date + + if ((typeof date).toString().toLowerCase() === 'string') { + try { + + date = datetime.parseISO8601Date(date, { toLocal: true }); + + } catch (err) { + return date; + } } - return datetime.getDisplayTime(date).toLowerCase() + + return datetime.getDisplayTime(date).toLowerCase(); } function getTimeslotHeadersHtml(startDate, endDateTime) { - var html = ""; - for (startDate = new Date(startDate.getTime()), html += '
'; startDate.getTime() < endDateTime;) html += '
', html += getDisplayTime(startDate), html += "
", startDate.setTime(startDate.getTime() + cellDurationMs); - return html + + var html = ''; + + // clone + startDate = new Date(startDate.getTime()); + + html += '
'; + + while (startDate.getTime() < endDateTime) { + + html += '
'; + + html += getDisplayTime(startDate); + html += '
'; + + // Add 30 mins + startDate.setTime(startDate.getTime() + cellDurationMs); + } + + return html; } function parseDates(program) { - if (!program.StartDateLocal) try { - program.StartDateLocal = datetime.parseISO8601Date(program.StartDate, { - toLocal: !0 - }) - } catch (err) {} - if (!program.EndDateLocal) try { - program.EndDateLocal = datetime.parseISO8601Date(program.EndDate, { - toLocal: !0 - }) - } catch (err) {} - return null + + if (!program.StartDateLocal) { + try { + + program.StartDateLocal = datetime.parseISO8601Date(program.StartDate, { toLocal: true }); + + } catch (err) { + + } + + } + + if (!program.EndDateLocal) { + try { + + program.EndDateLocal = datetime.parseISO8601Date(program.EndDate, { toLocal: true }); + + } catch (err) { + + } + + } + + return null; } function getTimerIndicator(item) { + var status; - if ("SeriesTimer" === item.Type) return ''; - if (item.TimerId || item.SeriesTimerId) status = item.Status || "Cancelled"; - else { - if ("Timer" !== item.Type) return ""; - status = item.Status + + if (item.Type === 'SeriesTimer') { + return ''; } - return item.SeriesTimerId ? "Cancelled" !== status ? '' : '' : '' + else if (item.TimerId || item.SeriesTimerId) { + + status = item.Status || 'Cancelled'; + } + else if (item.Type === 'Timer') { + + status = item.Status; + } + else { + return ''; + } + + if (item.SeriesTimerId) { + + if (status !== 'Cancelled') { + return ''; + } + + return ''; + } + + return ''; } function getChannelProgramsHtml(context, date, channel, programs, options, listInfo) { - var html = "", - startMs = date.getTime(), - endMs = startMs + msPerDay - 1; - html += '
'; - for (var programsFound, clickAction = layoutManager.tv ? "link" : "programdialog", categories = self.categoryOptions.categories || [], displayMovieContent = !categories.length || -1 !== categories.indexOf("movies"), displaySportsContent = !categories.length || -1 !== categories.indexOf("sports"), displayNewsContent = !categories.length || -1 !== categories.indexOf("news"), displayKidsContent = !categories.length || -1 !== categories.indexOf("kids"), displaySeriesContent = !categories.length || -1 !== categories.indexOf("series"), enableColorCodedBackgrounds = "true" === userSettings.get("guide-colorcodedbackgrounds"), now = (new Date).getTime(), i = listInfo.startIndex, length = programs.length; i < length; i++) { + + var html = ''; + + var startMs = date.getTime(); + var endMs = startMs + msPerDay - 1; + + var outerCssClass = layoutManager.tv ? 'channelPrograms channelPrograms-tv' : 'channelPrograms'; + + html += '
'; + + var clickAction = layoutManager.tv ? 'link' : 'programdialog'; + + var categories = self.categoryOptions.categories || []; + var displayMovieContent = !categories.length || categories.indexOf('movies') !== -1; + var displaySportsContent = !categories.length || categories.indexOf('sports') !== -1; + var displayNewsContent = !categories.length || categories.indexOf('news') !== -1; + var displayKidsContent = !categories.length || categories.indexOf('kids') !== -1; + var displaySeriesContent = !categories.length || categories.indexOf('series') !== -1; + var enableColorCodedBackgrounds = userSettings.get('guide-colorcodedbackgrounds') === 'true'; + + var programsFound; + var now = new Date().getTime(); + + for (var i = listInfo.startIndex, length = programs.length; i < length; i++) { + var program = programs[i]; - if (program.ChannelId === channel.Id) { - programsFound = !0, listInfo.startIndex++, parseDates(program); - var startDateLocalMs = program.StartDateLocal.getTime(), - endDateLocalMs = program.EndDateLocal.getTime(); - if (!(endDateLocalMs < startMs)) { - if (startDateLocalMs > endMs) break; - items[program.Id] = program; - var renderStartMs = Math.max(startDateLocalMs, startMs), - startPercent = (startDateLocalMs - startMs) / msPerDay; - startPercent *= 100, startPercent = Math.max(startPercent, 0); - var renderEndMs = Math.min(endDateLocalMs, endMs), - endPercent = (renderEndMs - renderStartMs) / msPerDay; - endPercent *= 100; - var cssClass = "programCell itemAction", - accentCssClass = null, - displayInnerContent = !0; - program.IsKids ? (displayInnerContent = displayKidsContent, accentCssClass = "kids") : program.IsSports ? (displayInnerContent = displaySportsContent, accentCssClass = "sports") : program.IsNews ? (displayInnerContent = displayNewsContent, accentCssClass = "news") : program.IsMovie ? (displayInnerContent = displayMovieContent, accentCssClass = "movie") : displayInnerContent = program.IsSeries ? displaySeriesContent : displayMovieContent && displayNewsContent && displaySportsContent && displayKidsContent && displaySeriesContent, displayInnerContent && enableColorCodedBackgrounds && accentCssClass && (cssClass += " programCell-" + accentCssClass), now >= startDateLocalMs && now < endDateLocalMs && (cssClass += " programCell-active"); - var timerAttributes = ""; - program.TimerId && (timerAttributes += ' data-timerid="' + program.TimerId + '"'), program.SeriesTimerId && (timerAttributes += ' data-seriestimerid="' + program.SeriesTimerId + '"'); - if (html += "= 2 ? ' is="emby-programcell"' : "") + ' data-action="' + clickAction + '"' + timerAttributes + ' data-channelid="' + program.ChannelId + '" data-id="' + program.Id + '" data-serverid="' + program.ServerId + '" data-startdate="' + program.StartDate + '" data-enddate="' + program.EndDate + '" data-type="' + program.Type + '" class="' + cssClass + '" style="left:' + startPercent + "%;width:" + endPercent + '%;">', displayInnerContent) { - html += '
', html += '
', html += '
' + program.Name; - var indicatorHtml = null; - program.IsLive && options.showLiveIndicator ? indicatorHtml = '' + globalize.translate("sharedcomponents#Live") + "" : program.IsPremiere && options.showPremiereIndicator ? indicatorHtml = '' + globalize.translate("sharedcomponents#Premiere") + "" : program.IsSeries && !program.IsRepeat && options.showNewIndicator ? indicatorHtml = '' + globalize.translate("sharedcomponents#AttributeNew") + "" : program.IsSeries && program.IsRepeat && options.showRepeatIndicator && (indicatorHtml = '' + globalize.translate("sharedcomponents#Repeat") + ""), html += indicatorHtml || "", program.EpisodeTitle && options.showEpisodeTitle && (html += '
', program.EpisodeTitle && options.showEpisodeTitle && (html += '' + program.EpisodeTitle + ""), html += "
"), html += "
", program.IsHD && options.showHdIcon && (layoutManager.tv ? html += '
HD
' : html += '
HD
'), html += getTimerIndicator(program), html += "
" - } - html += "" + + if (program.ChannelId !== channel.Id) { + + if (programsFound) { + break; } - } else if (programsFound) break + + continue; + } + + programsFound = true; + listInfo.startIndex++; + + parseDates(program); + + var startDateLocalMs = program.StartDateLocal.getTime(); + var endDateLocalMs = program.EndDateLocal.getTime(); + + if (endDateLocalMs < startMs) { + continue; + } + + if (startDateLocalMs > endMs) { + break; + } + + items[program.Id] = program; + + var renderStartMs = Math.max(startDateLocalMs, startMs); + var startPercent = (startDateLocalMs - startMs) / msPerDay; + startPercent *= 100; + startPercent = Math.max(startPercent, 0); + + var renderEndMs = Math.min(endDateLocalMs, endMs); + var endPercent = (renderEndMs - renderStartMs) / msPerDay; + endPercent *= 100; + + var cssClass = "programCell itemAction"; + var accentCssClass = null; + var displayInnerContent = true; + + if (program.IsKids) { + displayInnerContent = displayKidsContent; + accentCssClass = 'kids'; + } else if (program.IsSports) { + displayInnerContent = displaySportsContent; + accentCssClass = 'sports'; + } else if (program.IsNews) { + displayInnerContent = displayNewsContent; + accentCssClass = 'news'; + } else if (program.IsMovie) { + displayInnerContent = displayMovieContent; + accentCssClass = 'movie'; + } + else if (program.IsSeries) { + displayInnerContent = displaySeriesContent; + } + else { + displayInnerContent = displayMovieContent && displayNewsContent && displaySportsContent && displayKidsContent && displaySeriesContent; + } + + if (displayInnerContent && enableColorCodedBackgrounds && accentCssClass) { + cssClass += " programCell-" + accentCssClass; + } + + if (now >= startDateLocalMs && now < endDateLocalMs) { + cssClass += " programCell-active"; + } + + var timerAttributes = ''; + if (program.TimerId) { + timerAttributes += ' data-timerid="' + program.TimerId + '"'; + } + if (program.SeriesTimerId) { + timerAttributes += ' data-seriestimerid="' + program.SeriesTimerId + '"'; + } + + var isAttribute = endPercent >= 2 ? ' is="emby-programcell"' : ''; + + html += ''; + + if (displayInnerContent) { + var guideProgramNameClass = "guideProgramName"; + + html += '
'; + + html += '
'; + + html += '
' + program.Name; + + var indicatorHtml = null; + if (program.IsLive && options.showLiveIndicator) { + indicatorHtml = '' + globalize.translate('sharedcomponents#Live') + ''; + } + else if (program.IsPremiere && options.showPremiereIndicator) { + indicatorHtml = '' + globalize.translate('sharedcomponents#Premiere') + ''; + } + else if (program.IsSeries && !program.IsRepeat && options.showNewIndicator) { + indicatorHtml = '' + globalize.translate('sharedcomponents#AttributeNew') + ''; + } + else if (program.IsSeries && program.IsRepeat && options.showRepeatIndicator) { + indicatorHtml = '' + globalize.translate('sharedcomponents#Repeat') + ''; + } + html += indicatorHtml || ''; + + if ((program.EpisodeTitle && options.showEpisodeTitle)) { + html += '
'; + + if (program.EpisodeTitle && options.showEpisodeTitle) { + html += '' + program.EpisodeTitle + ''; + } + html += '
'; + } + + html += '
'; + + if (program.IsHD && options.showHdIcon) { + //html += 'hd'; + if (layoutManager.tv) { + html += '
HD
'; + } else { + html += '
HD
'; + } + } + + html += getTimerIndicator(program); + + html += '
'; + } + + html += ''; } - return html += "
" + + html += '
'; + + return html; } + function renderChannelHeaders(context, channels, apiClient) { - for (var html = "", i = 0, length = channels.length; i < length; i++) { - var channel = channels[i], - hasChannelImage = channel.ImageTags.Primary, - cssClass = "guide-channelHeaderCell itemAction"; - layoutManager.tv && (cssClass += " guide-channelHeaderCell-tv"); + + var html = ''; + + for (var i = 0, length = channels.length; i < length; i++) { + + var channel = channels[i]; + var hasChannelImage = channel.ImageTags.Primary; + + var cssClass = 'guide-channelHeaderCell itemAction'; + + if (layoutManager.tv) { + cssClass += ' guide-channelHeaderCell-tv'; + } + var title = []; - if (channel.ChannelNumber && title.push(channel.ChannelNumber), channel.Name && title.push(channel.Name), html += '" + + if (channel.ChannelNumber) { + + html += '

' + channel.ChannelNumber + '

'; + } + + if (!hasChannelImage && channel.Name) { + html += '
' + channel.Name + '
'; + } + + html += ''; } - var channelList = context.querySelector(".channelsContainer"); - channelList.innerHTML = html, imageLoader.lazyChildren(channelList) + + var channelList = context.querySelector('.channelsContainer'); + channelList.innerHTML = html; + imageLoader.lazyChildren(channelList); } function renderPrograms(context, date, channels, programs, options) { - for (var listInfo = { - startIndex: 0 - }, html = [], i = 0, length = channels.length; i < length; i++) html.push(getChannelProgramsHtml(context, date, channels[i], programs, options, listInfo)); - programGrid.innerHTML = html.join(""), programCells = programGrid.querySelectorAll("[is=emby-programcell]"), updateProgramCellsOnScroll(programGrid, programCells) + + var listInfo = { + startIndex: 0 + }; + + var html = []; + + for (var i = 0, length = channels.length; i < length; i++) { + + html.push(getChannelProgramsHtml(context, date, channels[i], programs, options, listInfo)); + } + + programGrid.innerHTML = html.join(''); + + programCells = programGrid.querySelectorAll('[is=emby-programcell]'); + + updateProgramCellsOnScroll(programGrid, programCells); } function getProgramSortOrder(program, channels) { - for (var channelId = program.ChannelId, channelIndex = -1, i = 0, length = channels.length; i < length; i++) + + var channelId = program.ChannelId; + var channelIndex = -1; + + for (var i = 0, length = channels.length; i < length; i++) { if (channelId === channels[i].Id) { channelIndex = i; - break - } return 1e7 * channelIndex + datetime.parseISO8601Date(program.StartDate, { - toLocal: !0 - }).getTime() / 6e4 + break; + } + } + + var start = datetime.parseISO8601Date(program.StartDate, { toLocal: true }); + + return (channelIndex * 10000000) + (start.getTime() / 60000); } function renderGuide(context, date, channels, programs, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) { - programs.sort(function(a, b) { - return getProgramSortOrder(a, channels) - getProgramSortOrder(b, channels) + + programs.sort(function (a, b) { + return getProgramSortOrder(a, channels) - getProgramSortOrder(b, channels); }); - var activeElement = document.activeElement, - itemId = activeElement && activeElement.getAttribute ? activeElement.getAttribute("data-id") : null, - channelRowId = null; - activeElement && (channelRowId = dom.parentWithClass(activeElement, "channelPrograms"), channelRowId = channelRowId && channelRowId.getAttribute ? channelRowId.getAttribute("data-channelid") : null), renderChannelHeaders(context, channels, apiClient); - var startDate = date, - endDate = new Date(startDate.getTime() + msPerDay); - context.querySelector(".timeslotHeaders").innerHTML = getTimeslotHeadersHtml(startDate, endDate), items = {}, renderPrograms(context, date, channels, programs, renderOptions), focusProgramOnRender && focusProgram(context, itemId, channelRowId, focusToTimeMs, startTimeOfDayMs), scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs) + + var activeElement = document.activeElement; + var itemId = activeElement && activeElement.getAttribute ? activeElement.getAttribute('data-id') : null; + var channelRowId = null; + + if (activeElement) { + channelRowId = dom.parentWithClass(activeElement, 'channelPrograms'); + channelRowId = channelRowId && channelRowId.getAttribute ? channelRowId.getAttribute('data-channelid') : null; + } + + renderChannelHeaders(context, channels, apiClient); + + var startDate = date; + var endDate = new Date(startDate.getTime() + msPerDay); + context.querySelector('.timeslotHeaders').innerHTML = getTimeslotHeadersHtml(startDate, endDate); + items = {}; + renderPrograms(context, date, channels, programs, renderOptions); + + if (focusProgramOnRender) { + focusProgram(context, itemId, channelRowId, focusToTimeMs, startTimeOfDayMs); + } + + scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs); } function scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs) { + scrollToTimeMs -= startTimeOfDayMs; + var pct = scrollToTimeMs / msPerDay; + programGrid.scrollTop = 0; + var scrollPos = pct * programGrid.scrollWidth; - nativeScrollTo(programGrid, scrollPos, !0) + + nativeScrollTo(programGrid, scrollPos, true); } function focusProgram(context, itemId, channelRowId, focusToTimeMs, startTimeOfDayMs) { + var focusElem; - if (itemId && (focusElem = context.querySelector('[data-id="' + itemId + '"]')), focusElem) focusManager.focus(focusElem); - else { + if (itemId) { + focusElem = context.querySelector('[data-id="' + itemId + '"]'); + } + + if (focusElem) { + focusManager.focus(focusElem); + } else { + var autoFocusParent; - channelRowId && (autoFocusParent = context.querySelector('[data-channelid="' + channelRowId + '"]')), autoFocusParent || (autoFocusParent = programGrid), focusToTimeMs -= startTimeOfDayMs; - for (var pct = focusToTimeMs / msPerDay * 100, programCell = autoFocusParent.querySelector(".programCell"); programCell;) { - var left = (programCell.style.left || "").replace("%", ""); - left = left ? parseFloat(left) : 0; - var width = (programCell.style.width || "").replace("%", ""); - if (width = width ? parseFloat(width) : 0, left >= pct || left + width >= pct) break; - programCell = programCell.nextSibling + + if (channelRowId) { + autoFocusParent = context.querySelector('[data-channelid="' + channelRowId + '"]'); + } + + if (!autoFocusParent) { + autoFocusParent = programGrid; + } + + focusToTimeMs -= startTimeOfDayMs; + + var pct = (focusToTimeMs / msPerDay) * 100; + + var programCell = autoFocusParent.querySelector('.programCell'); + + while (programCell) { + + var left = (programCell.style.left || '').replace('%', ''); + left = left ? parseFloat(left) : 0; + var width = (programCell.style.width || '').replace('%', ''); + width = width ? parseFloat(width) : 0; + + if (left >= pct || (left + width) >= pct) { + break; + } + programCell = programCell.nextSibling; + } + + if (programCell) { + focusManager.focus(programCell); + } else { + focusManager.autoFocus(autoFocusParent, true); } - programCell ? focusManager.focus(programCell) : focusManager.autoFocus(autoFocusParent, !0) } } function nativeScrollTo(container, pos, horizontal) { - container.scrollTo ? horizontal ? container.scrollTo(pos, 0) : container.scrollTo(0, pos) : horizontal ? container.scrollLeft = Math.round(pos) : container.scrollTop = Math.round(pos) + + if (container.scrollTo) { + if (horizontal) { + container.scrollTo(pos, 0); + } else { + container.scrollTo(0, pos); + } + } else { + if (horizontal) { + container.scrollLeft = Math.round(pos); + } else { + container.scrollTop = Math.round(pos); + } + } } + var lastGridScroll = 0; + var lastHeaderScroll = 0; + var scrollXPct = 0; function onProgramGridScroll(context, elem, timeslotHeaders) { - if ((new Date).getTime() - lastHeaderScroll >= 1e3) { - lastGridScroll = (new Date).getTime(); + + if ((new Date().getTime() - lastHeaderScroll) >= 1000) { + lastGridScroll = new Date().getTime(); + var scrollLeft = elem.scrollLeft; - scrollXPct = 100 * scrollLeft / elem.scrollWidth, nativeScrollTo(timeslotHeaders, scrollLeft, !0) + scrollXPct = (scrollLeft * 100) / elem.scrollWidth; + nativeScrollTo(timeslotHeaders, scrollLeft, true); } - updateProgramCellsOnScroll(elem, programCells) + + updateProgramCellsOnScroll(elem, programCells); } function onTimeslotHeadersScroll(context, elem) { - (new Date).getTime() - lastGridScroll >= 1e3 && (lastHeaderScroll = (new Date).getTime(), nativeScrollTo(programGrid, elem.scrollLeft, !0)) + + if ((new Date().getTime() - lastGridScroll) >= 1000) { + lastHeaderScroll = new Date().getTime(); + nativeScrollTo(programGrid, elem.scrollLeft, true); + } } function changeDate(page, date, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) { + var newStartDate = normalizeDateToTimeslot(date); - currentDate = newStartDate, reloadGuide(page, newStartDate, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) + currentDate = newStartDate; + + reloadGuide(page, newStartDate, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender); } 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", - html = '" + + var cssClass = isActive ? 'emby-tab-button guide-date-tab-button emby-tab-button-active' : 'emby-tab-button guide-date-tab-button'; + + var html = ''; + + return html; } function setDateRange(page, guideInfo) { - var today = new Date, - nowHours = today.getHours(); + + var today = new Date(); + var nowHours = today.getHours(); today.setHours(nowHours, 0, 0, 0); - var start = datetime.parseISO8601Date(guideInfo.StartDate, { - toLocal: !0 - }), - end = datetime.parseISO8601Date(guideInfo.EndDate, { - toLocal: !0 - }); - start.setHours(nowHours, 0, 0, 0), end.setHours(0, 0, 0, 0), start.getTime() >= end.getTime() && end.setDate(start.getDate() + 1), start = new Date(Math.max(today, start)); - var dateTabsHtml = "", - tabIndex = 0, - date = new Date; - currentDate && date.setTime(currentDate.getTime()), date.setHours(nowHours, 0, 0, 0); - var startTimeOfDayMs = 60 * start.getHours() * 60 * 1e3; - for (startTimeOfDayMs += 60 * start.getMinutes() * 1e3; start <= end;) { - dateTabsHtml += getDateTabText(start, date.getDate() === start.getDate() && date.getMonth() === start.getMonth() && date.getFullYear() === start.getFullYear(), tabIndex), start.setDate(start.getDate() + 1), start.setHours(0, 0, 0, 0), tabIndex++ + + var start = datetime.parseISO8601Date(guideInfo.StartDate, { toLocal: true }); + var end = datetime.parseISO8601Date(guideInfo.EndDate, { toLocal: true }); + + start.setHours(nowHours, 0, 0, 0); + end.setHours(0, 0, 0, 0); + + if (start.getTime() >= end.getTime()) { + end.setDate(start.getDate() + 1); } - page.querySelector(".emby-tabs-slider").innerHTML = dateTabsHtml, page.querySelector(".guideDateTabs").refresh(); - var newDate = new Date, - newDateHours = newDate.getHours(), - scrollToTimeMs = 60 * newDateHours * 60 * 1e3, - minutes = newDate.getMinutes(); - minutes >= 30 && (scrollToTimeMs += 18e5), changeDate(page, date, scrollToTimeMs, 60 * (60 * newDateHours + minutes) * 1e3, startTimeOfDayMs, layoutManager.tv) + + start = new Date(Math.max(today, start)); + + var dateTabsHtml = ''; + var tabIndex = 0; + + var date = new Date(); + + if (currentDate) { + date.setTime(currentDate.getTime()); + } + + date.setHours(nowHours, 0, 0, 0); + //start.setHours(0, 0, 0, 0); + + var startTimeOfDayMs = (start.getHours() * 60 * 60 * 1000); + startTimeOfDayMs += start.getMinutes() * 60 * 1000; + + 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(); + + var newDate = new Date(); + var newDateHours = newDate.getHours(); + var scrollToTimeMs = newDateHours * 60 * 60 * 1000; + + var minutes = newDate.getMinutes(); + if (minutes >= 30) { + scrollToTimeMs += 30 * 60 * 1000; + } + + var focusToTimeMs = ((newDateHours * 60) + minutes) * 60 * 1000; + changeDate(page, date, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, layoutManager.tv); } function reloadPage(page) { - showLoading(), connectionManager.getApiClient(options.serverId).getLiveTvGuideInfo().then(function(guideInfo) { - setDateRange(page, guideInfo) - }) + + showLoading(); + + var apiClient = connectionManager.getApiClient(options.serverId); + + apiClient.getLiveTvGuideInfo().then(function (guideInfo) { + + setDateRange(page, guideInfo); + }); } function getChannelProgramsFocusableElements(container) { - for (var elements = container.querySelectorAll(".programCell"), list = [], currentScrollXPct = scrollXPct + 1, i = 0, length = elements.length; i < length; i++) { - var elem = elements[i], - left = (elem.style.left || "").replace("%", ""); + + var elements = container.querySelectorAll('.programCell'); + + var list = []; + // add 1 to avoid programs that are out of view to the left + var currentScrollXPct = scrollXPct + 1; + + for (var i = 0, length = elements.length; i < length; i++) { + + var elem = elements[i]; + + var left = (elem.style.left || '').replace('%', ''); left = left ? parseFloat(left) : 0; - var width = (elem.style.width || "").replace("%", ""); - width = width ? parseFloat(width) : 0, left + width >= currentScrollXPct && list.push(elem) + var width = (elem.style.width || '').replace('%', ''); + width = width ? parseFloat(width) : 0; + + if ((left + width) >= currentScrollXPct) { + list.push(elem); + } } - return list + + return list; } function onInputCommand(e) { - var container, channelPrograms, focusableElements, newRow, target = e.target, - programCell = dom.parentWithClass(target, "programCell"); + + var target = e.target; + var programCell = dom.parentWithClass(target, 'programCell'); + var container; + var channelPrograms; + var focusableElements; + var newRow; + + var scrollX = false; + switch (e.detail.command) { - case "up": - programCell ? (container = programGrid, channelPrograms = dom.parentWithClass(programCell, "channelPrograms"), newRow = channelPrograms.previousSibling, newRow ? (focusableElements = getChannelProgramsFocusableElements(newRow), focusableElements.length ? container = newRow : focusableElements = null) : container = null) : container = null, lastFocusDirection = e.detail.command, focusManager.moveUp(target, { + + case 'up': + if (programCell) { + container = programGrid; + channelPrograms = dom.parentWithClass(programCell, 'channelPrograms'); + + newRow = channelPrograms.previousSibling; + if (newRow) { + focusableElements = getChannelProgramsFocusableElements(newRow); + if (focusableElements.length) { + container = newRow; + } else { + focusableElements = null; + } + } else { + container = null; + } + } else { + container = null; + } + lastFocusDirection = e.detail.command; + + focusManager.moveUp(target, { container: container, focusableElements: focusableElements }); break; - case "down": - programCell ? (container = programGrid, channelPrograms = dom.parentWithClass(programCell, "channelPrograms"), newRow = channelPrograms.nextSibling, newRow ? (focusableElements = getChannelProgramsFocusableElements(newRow), focusableElements.length ? container = newRow : focusableElements = null) : container = null) : container = null, lastFocusDirection = e.detail.command, focusManager.moveDown(target, { + case 'down': + if (programCell) { + container = programGrid; + channelPrograms = dom.parentWithClass(programCell, 'channelPrograms'); + + newRow = channelPrograms.nextSibling; + if (newRow) { + focusableElements = getChannelProgramsFocusableElements(newRow); + if (focusableElements.length) { + container = newRow; + } else { + focusableElements = null; + } + } else { + container = null; + } + } else { + container = null; + } + lastFocusDirection = e.detail.command; + + focusManager.moveDown(target, { container: container, focusableElements: focusableElements }); break; - case "left": - container = programCell ? dom.parentWithClass(programCell, "channelPrograms") : null, container && !programCell.previousSibling && (container = null), lastFocusDirection = e.detail.command, focusManager.moveLeft(target, { + case 'left': + container = programCell ? dom.parentWithClass(programCell, 'channelPrograms') : null; + // allow left outside the channelProgramsContainer when the first child is currently focused + if (container && !programCell.previousSibling) { + container = null; + } + lastFocusDirection = e.detail.command; + + focusManager.moveLeft(target, { container: container - }), !0; + }); + scrollX = true; break; - case "right": - container = programCell ? dom.parentWithClass(programCell, "channelPrograms") : null, lastFocusDirection = e.detail.command, focusManager.moveRight(target, { + case 'right': + container = programCell ? dom.parentWithClass(programCell, 'channelPrograms') : null; + lastFocusDirection = e.detail.command; + + focusManager.moveRight(target, { container: container - }), !0; + }); + scrollX = true; break; default: - return + return; } - e.preventDefault(), e.stopPropagation() + + e.preventDefault(); + e.stopPropagation(); } function onScrollerFocus(e) { - var target = e.target, - programCell = dom.parentWithClass(target, "programCell"); + + var target = e.target; + var programCell = dom.parentWithClass(target, 'programCell'); + if (programCell) { - var focused = target, - id = focused.getAttribute("data-id"), - item = items[id]; - item && events.trigger(self, "focus", [{ - item: item - }]) + var focused = target; + + var id = focused.getAttribute('data-id'); + var item = items[id]; + + if (item) { + events.trigger(self, 'focus', [ + { + item: item + }]); + } } - if ("left" === lastFocusDirection) programCell && scrollHelper.toStart(programGrid, programCell, !0, !0); - else if ("right" === lastFocusDirection) programCell && scrollHelper.toCenter(programGrid, programCell, !0, !0); - else if ("up" === lastFocusDirection || "down" === lastFocusDirection) { - var verticalScroller = dom.parentWithClass(target, "guideVerticalScroller"); + + if (lastFocusDirection === 'left') { + + if (programCell) { + + scrollHelper.toStart(programGrid, programCell, true, true); + } + } + + else if (lastFocusDirection === 'right') { + + if (programCell) { + + scrollHelper.toCenter(programGrid, programCell, true, true); + } + } + + else if (lastFocusDirection === 'up' || lastFocusDirection === 'down') { + + var verticalScroller = dom.parentWithClass(target, 'guideVerticalScroller'); if (verticalScroller) { - var focusedElement = programCell || dom.parentWithTag(target, "BUTTON"); - verticalScroller.toCenter(focusedElement, !0) + + var focusedElement = programCell || dom.parentWithTag(target, 'BUTTON'); + verticalScroller.toCenter(focusedElement, true); } } } function setScrollEvents(view, enabled) { + if (layoutManager.tv) { - var guideVerticalScroller = view.querySelector(".guideVerticalScroller"); - enabled ? inputManager.on(guideVerticalScroller, onInputCommand) : inputManager.off(guideVerticalScroller, onInputCommand) + var guideVerticalScroller = view.querySelector('.guideVerticalScroller'); + + if (enabled) { + inputManager.on(guideVerticalScroller, onInputCommand); + } else { + inputManager.off(guideVerticalScroller, onInputCommand); + } } } function onTimerCreated(e, apiClient, data) { - for (var programId = data.ProgramId, newTimerId = data.Id, cells = options.element.querySelectorAll('.programCell[data-id="' + programId + '"]'), i = 0, length = cells.length; i < length; i++) { + + var programId = data.ProgramId; + // This could be null, not supported by all tv providers + var newTimerId = data.Id; + + // find guide cells by program id, ensure timer icon + var cells = options.element.querySelectorAll('.programCell[data-id="' + programId + '"]'); + for (var i = 0, length = cells.length; i < length; i++) { var cell = cells[i]; - cell.querySelector(".timerIcon") || cell.querySelector(".guideProgramName").insertAdjacentHTML("beforeend", ''), newTimerId && cell.setAttribute("data-timerid", newTimerId) + + var icon = cell.querySelector('.timerIcon'); + if (!icon) { + cell.querySelector('.guideProgramName').insertAdjacentHTML('beforeend', ''); + } + + if (newTimerId) { + cell.setAttribute('data-timerid', newTimerId); + } } } - function onSeriesTimerCreated(e, apiClient, data) {} + function onSeriesTimerCreated(e, apiClient, data) { + } function onTimerCancelled(e, apiClient, data) { - for (var id = data.Id, cells = options.element.querySelectorAll('.programCell[data-timerid="' + id + '"]'), i = 0, length = cells.length; i < length; i++) { - var cell = cells[i], - icon = cell.querySelector(".timerIcon"); - icon && icon.parentNode.removeChild(icon), cell.removeAttribute("data-timerid") + var id = data.Id; + // find guide cells by timer id, remove timer icon + var cells = options.element.querySelectorAll('.programCell[data-timerid="' + id + '"]'); + for (var i = 0, length = cells.length; i < length; i++) { + var cell = cells[i]; + var icon = cell.querySelector('.timerIcon'); + if (icon) { + icon.parentNode.removeChild(icon); + } + cell.removeAttribute('data-timerid'); } } function onSeriesTimerCancelled(e, apiClient, data) { - for (var id = data.Id, cells = options.element.querySelectorAll('.programCell[data-seriestimerid="' + id + '"]'), i = 0, length = cells.length; i < length; i++) { - var cell = cells[i], - icon = cell.querySelector(".seriesTimerIcon"); - icon && icon.parentNode.removeChild(icon), cell.removeAttribute("data-seriestimerid") + var id = data.Id; + // find guide cells by timer id, remove timer icon + var cells = options.element.querySelectorAll('.programCell[data-seriestimerid="' + id + '"]'); + for (var i = 0, length = cells.length; i < length; i++) { + var cell = cells[i]; + var icon = cell.querySelector('.seriesTimerIcon'); + if (icon) { + icon.parentNode.removeChild(icon); + } + cell.removeAttribute('data-seriestimerid'); } } - var self = this, - items = {}; - self.options = options, self.categoryOptions = { - categories: [] - }; - var currentDate, autoRefreshInterval, programCells, lastFocusDirection, programGrid, cellCurationMinutes = 30, - cellDurationMs = 60 * cellCurationMinutes * 1e3, - msPerDay = 864e5, - currentStartIndex = 0, - currentChannelLimit = 0; - self.refresh = function() { - currentDate = null, reloadPage(options.element), restartAutoRefresh() - }, self.pause = function() { - stopAutoRefresh() - }, self.resume = function(refreshData) { - refreshData ? self.refresh() : restartAutoRefresh() - }, self.destroy = function() { - stopAutoRefresh(), events.off(serverNotifications, "TimerCreated", onTimerCreated), events.off(serverNotifications, "SeriesTimerCreated", onSeriesTimerCreated), events.off(serverNotifications, "TimerCancelled", onTimerCancelled), events.off(serverNotifications, "SeriesTimerCancelled", onSeriesTimerCancelled), setScrollEvents(options.element, !1), itemShortcuts.off(options.element), items = {} - }; - var lastGridScroll = 0, - lastHeaderScroll = 0, - scrollXPct = 0; - require(["text!./tvguide.template.html"], function(template) { + + require(['text!./tvguide.template.html'], function (template) { + var context = options.element; - context.classList.add("tvguide"), context.innerHTML = globalize.translateDocument(template, "sharedcomponents"), programGrid = context.querySelector(".programGrid"); - var timeslotHeaders = context.querySelector(".timeslotHeaders"); - layoutManager.tv ? dom.addEventListener(context.querySelector(".guideVerticalScroller"), "focus", onScrollerFocus, { - capture: !0, - passive: !0 - }) : layoutManager.desktop && timeslotHeaders.classList.add("timeslotHeaders-desktop"), (browser.iOS || browser.osx) && (context.querySelector(".channelsContainer").classList.add("noRubberBanding"), programGrid.classList.add("noRubberBanding")), dom.addEventListener(programGrid, "scroll", function(e) { - onProgramGridScroll(context, this, timeslotHeaders) + + context.classList.add('tvguide'); + + context.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + programGrid = context.querySelector('.programGrid'); + var timeslotHeaders = context.querySelector('.timeslotHeaders'); + + if (layoutManager.tv) { + dom.addEventListener(context.querySelector('.guideVerticalScroller'), 'focus', onScrollerFocus, { + capture: true, + passive: true + }); + } else if (layoutManager.desktop) { + timeslotHeaders.classList.add('timeslotHeaders-desktop'); + } + + if (browser.iOS || browser.osx) { + context.querySelector('.channelsContainer').classList.add('noRubberBanding'); + + programGrid.classList.add('noRubberBanding'); + } + + dom.addEventListener(programGrid, 'scroll', function (e) { + onProgramGridScroll(context, this, timeslotHeaders); }, { - passive: !0 - }), dom.addEventListener(timeslotHeaders, "scroll", function() { - onTimeslotHeadersScroll(context, this) + passive: true + }); + + dom.addEventListener(timeslotHeaders, 'scroll', function () { + onTimeslotHeadersScroll(context, this); }, { - passive: !0 - }), programGrid.addEventListener("click", onProgramGridClick), 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(".guideDateTabs").addEventListener("tabchange", function(e) { - var allTabButtons = e.target.querySelectorAll(".guide-date-tab-button"), - tabButton = allTabButtons[parseInt(e.detail.selectedTabIndex)]; + passive: true + }); + + programGrid.addEventListener('click', onProgramGridClick); + + 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('.guideDateTabs').addEventListener('tabchange', function (e) { + + var allTabButtons = e.target.querySelectorAll('.guide-date-tab-button'); + + var tabButton = allTabButtons[parseInt(e.detail.selectedTabIndex)]; if (tabButton) { - var previousButton = null == e.detail.previousIndex ? null : allTabButtons[parseInt(e.detail.previousIndex)], - date = new Date; - date.setTime(parseInt(tabButton.getAttribute("data-date"))); - var scrollToTimeMs, scrollWidth = programGrid.scrollWidth; - if (scrollToTimeMs = scrollWidth ? programGrid.scrollLeft / scrollWidth * msPerDay : 0, previousButton) { - var previousDate = new Date; - previousDate.setTime(parseInt(previousButton.getAttribute("data-date"))), scrollToTimeMs += 60 * previousDate.getHours() * 60 * 1e3, scrollToTimeMs += 60 * previousDate.getMinutes() * 1e3 + + var previousButton = e.detail.previousIndex == null ? null : allTabButtons[parseInt(e.detail.previousIndex)]; + + var date = new Date(); + date.setTime(parseInt(tabButton.getAttribute('data-date'))); + + var scrollWidth = programGrid.scrollWidth; + var scrollToTimeMs; + if (scrollWidth) { + scrollToTimeMs = (programGrid.scrollLeft / scrollWidth) * msPerDay; + } else { + scrollToTimeMs = 0; } - var startTimeOfDayMs = 60 * date.getHours() * 60 * 1e3; - startTimeOfDayMs += 60 * date.getMinutes() * 1e3, changeDate(context, date, scrollToTimeMs, scrollToTimeMs, startTimeOfDayMs, !1) + + if (previousButton) { + + var previousDate = new Date(); + previousDate.setTime(parseInt(previousButton.getAttribute('data-date'))); + + scrollToTimeMs += (previousDate.getHours() * 60 * 60 * 1000); + scrollToTimeMs += (previousDate.getMinutes() * 60 * 1000); + } + + var startTimeOfDayMs = (date.getHours() * 60 * 60 * 1000); + startTimeOfDayMs += (date.getMinutes() * 60 * 1000); + + changeDate(context, date, scrollToTimeMs, scrollToTimeMs, startTimeOfDayMs, false); } - }), setScrollEvents(context, !0), itemShortcuts.on(context), events.trigger(self, "load"), events.on(serverNotifications, "TimerCreated", onTimerCreated), events.on(serverNotifications, "SeriesTimerCreated", onSeriesTimerCreated), events.on(serverNotifications, "TimerCancelled", onTimerCancelled), events.on(serverNotifications, "SeriesTimerCancelled", onSeriesTimerCancelled), self.refresh() - }) + }); + + setScrollEvents(context, true); + itemShortcuts.on(context); + + events.trigger(self, 'load'); + + events.on(serverNotifications, 'TimerCreated', onTimerCreated); + events.on(serverNotifications, 'SeriesTimerCreated', onSeriesTimerCreated); + events.on(serverNotifications, 'TimerCancelled', onTimerCancelled); + events.on(serverNotifications, 'SeriesTimerCancelled', onSeriesTimerCancelled); + + self.refresh(); + }); } - var isUpdatingProgramCellScroll = !1, - ProgramCellPrototype = Object.create(HTMLButtonElement.prototype); - return ProgramCellPrototype.detachedCallback = function() { - this.posLeft = null, this.posWidth = null, this.guideProgramName = null - }, document.registerElement("emby-programcell", { + + var ProgramCellPrototype = Object.create(HTMLButtonElement.prototype); + + ProgramCellPrototype.detachedCallback = function () { + this.posLeft = null; + this.posWidth = null; + this.guideProgramName = null; + }; + + document.registerElement('emby-programcell', { prototype: ProgramCellPrototype, - extends: "button" - }), Guide + extends: 'button' + }); + + return Guide; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/guide/programs.css b/src/bower_components/emby-webcomponents/guide/programs.css index 2d8738e01a..7a559e173f 100644 --- a/src/bower_components/emby-webcomponents/guide/programs.css +++ b/src/bower_components/emby-webcomponents/guide/programs.css @@ -1,19 +1,19 @@ .newTvProgram { - background: #38c; - color: #fff + background: #3388cc; + color: #fff; } .liveTvProgram { - background: #c33; - color: #fff + background: #cc3333; + color: #fff; } .premiereTvProgram { background: #EF6C00; - color: #fff + color: #fff; } .repeatTvProgram { background: #009688; - color: #fff -} \ No newline at end of file + color: #fff; +} diff --git a/src/bower_components/emby-webcomponents/headroom/headroom.css b/src/bower_components/emby-webcomponents/headroom/headroom.css index 642426881a..caac40a1b6 100644 --- a/src/bower_components/emby-webcomponents/headroom/headroom.css +++ b/src/bower_components/emby-webcomponents/headroom/headroom.css @@ -1,15 +1,11 @@ .headroom { - -webkit-transition: -webkit-transform 140ms linear; - -o-transition: transform 140ms linear; - transition: transform 140ms linear + transition: transform 140ms linear; } .headroom--pinned { - -webkit-transform: none; - transform: none + transform: none; } .headroom--unpinned:not(.headroomDisabled) { - -webkit-transform: translateY(-100%); - transform: translateY(-100%) + transform: translateY(-100%); } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/headroom/headroom.js b/src/bower_components/emby-webcomponents/headroom/headroom.js index bd6573a663..9cb1cac04d 100644 --- a/src/bower_components/emby-webcomponents/headroom/headroom.js +++ b/src/bower_components/emby-webcomponents/headroom/headroom.js @@ -1,136 +1,349 @@ -define(["dom", "layoutManager", "browser", "css!./headroom"], function(dom, layoutManager, browser) { - "use strict"; +/*! + * headroom.js v0.7.0 - Give your page some headroom. Hide your header until you need it + * Copyright (c) 2014 Nick Williams - http://wicky.nillia.ms/headroom.js + * License: MIT + */ +define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, layoutManager, browser) { + + 'use strict'; + + /* exported features */ + + var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; + + /** + * Handles debouncing of events via requestAnimationFrame + * @see http://www.html5rocks.com/en/tutorials/speed/animations/ + * @param {Function} callback The callback to handle whichever event + */ function Debouncer(callback) { - this.callback = callback, this.ticking = !1 + this.callback = callback; + this.ticking = false; } + Debouncer.prototype = { + constructor: Debouncer, + + /** + * dispatches the event to the supplied callback + * @private + */ + update: function () { + if (this.callback) { + this.callback(); + } + this.ticking = false; + }, + + /** + * Attach this as the event listeners + */ + handleEvent: function () { + if (!this.ticking) { + requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))); + this.ticking = true; + } + } + }; function onHeadroomClearedExternally() { - this.state = null + this.state = null; } + /** + * UI enhancement for fixed headers. + * Hides header when scrolling down + * Shows header when scrolling up + * @constructor + * @param {DOMElement} elem the header element + * @param {Object} options options for the widget + */ function Headroom(elems, options) { - options = Object.assign(Headroom.options, options || {}), this.lastKnownScrollY = 0, this.elems = elems, this.scroller = options.scroller, this.debouncer = onScroll.bind(this), this.offset = options.offset, this.initialised = !1, this.initialClass = options.initialClass, this.unPinnedClass = options.unPinnedClass, this.pinnedClass = options.pinnedClass, this.state = "clear" + options = Object.assign(Headroom.options, options || {}); + + this.lastKnownScrollY = 0; + this.elems = elems; + + this.scroller = options.scroller; + + this.debouncer = onScroll.bind(this); + this.offset = options.offset; + this.initialised = false; + + this.initialClass = options.initialClass; + this.unPinnedClass = options.unPinnedClass; + this.pinnedClass = options.pinnedClass; + + this.state = 'clear'; } function onScroll() { - this.paused || requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))) - } - var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; - return Debouncer.prototype = { - constructor: Debouncer, - update: function() { - this.callback && this.callback(), this.ticking = !1 - }, - handleEvent: function() { - this.ticking || (requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))), this.ticking = !0) + + if (this.paused) { + return; } - }, Headroom.prototype = { + + requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))); + } + + Headroom.prototype = { constructor: Headroom, - init: function() { + + /** + * Initialises the widget + */ + init: function () { + if (browser.supportsCssAnimation()) { - for (var i = 0, length = this.elems.length; i < length; i++) this.elems[i].classList.add(this.initialClass), this.elems[i].addEventListener("clearheadroom", onHeadroomClearedExternally.bind(this)); - this.attachEvent() + for (var i = 0, length = this.elems.length; i < length; i++) { + this.elems[i].classList.add(this.initialClass); + this.elems[i].addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this)); + } + + this.attachEvent(); } - return this + + return this; }, - add: function(elem) { - browser.supportsCssAnimation() && (elem.classList.add(this.initialClass), elem.addEventListener("clearheadroom", onHeadroomClearedExternally.bind(this)), this.elems.push(elem)) + + add: function (elem) { + + if (browser.supportsCssAnimation()) { + elem.classList.add(this.initialClass); + elem.addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this)); + this.elems.push(elem); + } }, - remove: function(elem) { - elem.classList.remove(this.unPinnedClass), elem.classList.remove(this.initialClass), elem.classList.remove(this.pinnedClass); - var i = this.elems.indexOf(elem); - 1 !== i && this.elems.splice(i, 1) + + remove: function (elem) { + + elem.classList.remove(this.unPinnedClass); + elem.classList.remove(this.initialClass); + elem.classList.remove(this.pinnedClass); + + var i = this.elems.indexOf(elem); + if (i !== -1) { + this.elems.splice(i, 1); + } }, - pause: function() { - this.paused = !0 + + pause: function () { + this.paused = true; }, - resume: function() { - this.paused = !1 + + resume: function () { + this.paused = false; }, - destroy: function() { - this.initialised = !1; + + /** + * Unattaches events and removes any classes that were added + */ + destroy: function () { + + this.initialised = false; + + for (var i = 0, length = this.elems.length; i < length; i++) { + + var classList = this.elems[i].classList; + + classList.remove(this.unPinnedClass); + classList.remove(this.initialClass); + classList.remove(this.pinnedClass); + } + + var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : 'scroll'; + + dom.removeEventListener(this.scroller, scrollEventName, this.debouncer, { + capture: false, + passive: true + }); + }, + + /** + * Attaches the scroll event + * @private + */ + attachEvent: function () { + if (!this.initialised) { + this.lastKnownScrollY = this.getScrollY(); + this.initialised = true; + + var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : 'scroll'; + + dom.addEventListener(this.scroller, scrollEventName, this.debouncer, { + capture: false, + passive: true + }); + + this.update(); + } + }, + + /** + * Unpins the header if it's currently pinned + */ + clear: function () { + + if (this.state === 'clear') { + return; + } + + this.state = 'clear'; + + var unpinnedClass = this.unPinnedClass; + var pinnedClass = this.pinnedClass; + for (var i = 0, length = this.elems.length; i < length; i++) { var classList = this.elems[i].classList; - classList.remove(this.unPinnedClass), classList.remove(this.initialClass), classList.remove(this.pinnedClass) - } - var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : "scroll"; - dom.removeEventListener(this.scroller, scrollEventName, this.debouncer, { - capture: !1, - passive: !0 - }) - }, - attachEvent: function() { - if (!this.initialised) { - this.lastKnownScrollY = this.getScrollY(), this.initialised = !0; - var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : "scroll"; - dom.addEventListener(this.scroller, scrollEventName, this.debouncer, { - capture: !1, - passive: !0 - }), this.update() + + classList.remove(unpinnedClass); + //classList.remove(pinnedClass); } }, - clear: function() { - if ("clear" !== this.state) { - this.state = "clear"; - for (var unpinnedClass = this.unPinnedClass, i = (this.pinnedClass, 0), length = this.elems.length; i < length; i++) { - this.elems[i].classList.remove(unpinnedClass) - } + + /** + * Unpins the header if it's currently pinned + */ + pin: function () { + + if (this.state === 'pin') { + return; + } + + this.state = 'pin'; + + var unpinnedClass = this.unPinnedClass; + var pinnedClass = this.pinnedClass; + + for (var i = 0, length = this.elems.length; i < length; i++) { + var classList = this.elems[i].classList; + + classList.remove(unpinnedClass); + classList.add(pinnedClass); } }, - pin: function() { - if ("pin" !== this.state) { - this.state = "pin"; - for (var unpinnedClass = this.unPinnedClass, pinnedClass = this.pinnedClass, i = 0, length = this.elems.length; i < length; i++) { - var classList = this.elems[i].classList; - classList.remove(unpinnedClass), classList.add(pinnedClass) - } + + /** + * Unpins the header if it's currently pinned + */ + unpin: function () { + + if (this.state === 'unpin') { + return; + } + + this.state = 'unpin'; + + var unpinnedClass = this.unPinnedClass; + var pinnedClass = this.pinnedClass; + + for (var i = 0, length = this.elems.length; i < length; i++) { + var classList = this.elems[i].classList; + + classList.add(unpinnedClass); + //classList.remove(pinnedClass); } }, - unpin: function() { - if ("unpin" !== this.state) { - this.state = "unpin"; - for (var unpinnedClass = this.unPinnedClass, i = (this.pinnedClass, 0), length = this.elems.length; i < length; i++) { - this.elems[i].classList.add(unpinnedClass) - } - } - }, - getScrollY: function() { + + /** + * Gets the Y scroll position + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY + * @return {Number} pixels the page has scrolled along the Y-axis + */ + getScrollY: function () { + var scroller = this.scroller; - if (scroller.getScrollPosition) return scroller.getScrollPosition(); + + if (scroller.getScrollPosition) { + return scroller.getScrollPosition(); + } + var pageYOffset = scroller.pageYOffset; - if (void 0 !== pageYOffset) return pageYOffset; + if (pageYOffset !== undefined) { + return pageYOffset; + } + var scrollTop = scroller.scrollTop; - return void 0 !== scrollTop ? scrollTop : (document.documentElement || document.body).scrollTop + if (scrollTop !== undefined) { + return scrollTop; + } + + return (document.documentElement || document.body).scrollTop; }, - shouldUnpin: function(currentScrollY) { + + /** + * determine if it is appropriate to unpin + * @param {int} currentScrollY the current y scroll position + * @return {bool} true if should unpin, false otherwise + */ + shouldUnpin: function (currentScrollY) { var scrollingDown = currentScrollY > this.lastKnownScrollY, pastOffset = currentScrollY >= this.offset; - return scrollingDown && pastOffset + + return scrollingDown && pastOffset; }, - shouldPin: function(currentScrollY) { + + /** + * determine if it is appropriate to pin + * @param {int} currentScrollY the current y scroll position + * @return {bool} true if should pin, false otherwise + */ + shouldPin: function (currentScrollY) { var scrollingUp = currentScrollY < this.lastKnownScrollY, pastOffset = currentScrollY <= this.offset; - return scrollingUp || pastOffset + + return scrollingUp || pastOffset; }, - update: function() { - if (!this.paused) { - var currentScrollY = this.getScrollY(), - lastKnownScrollY = this.lastKnownScrollY, - isTv = layoutManager.tv; - if (currentScrollY <= (isTv ? 120 : 10)) this.clear(); - else if (this.shouldUnpin(currentScrollY)) this.unpin(); - else if (this.shouldPin(currentScrollY)) { - var toleranceExceeded = Math.abs(currentScrollY - lastKnownScrollY) >= 14; - currentScrollY && isTv ? this.unpin() : toleranceExceeded && this.clear() - } - this.lastKnownScrollY = currentScrollY + + /** + * Handles updating the state of the widget + */ + update: function () { + + if (this.paused) { + return; } + + var currentScrollY = this.getScrollY(); + + var lastKnownScrollY = this.lastKnownScrollY; + + var isTv = layoutManager.tv; + + if (currentScrollY <= (isTv ? 120 : 10)) { + this.clear(); + } + else if (this.shouldUnpin(currentScrollY)) { + this.unpin(); + } + else if (this.shouldPin(currentScrollY)) { + + var toleranceExceeded = Math.abs(currentScrollY - lastKnownScrollY) >= 14; + + if (currentScrollY && isTv) { + this.unpin(); + } else if (toleranceExceeded) { + this.clear(); + } + } else if (isTv) { + //this.clear(); + } + + this.lastKnownScrollY = currentScrollY; } - }, Headroom.options = { + }; + /** + * Default options + * @type {Object} + */ + Headroom.options = { offset: 0, scroller: window, - initialClass: "headroom", - unPinnedClass: "headroom--unpinned", - pinnedClass: "headroom--pinned" - }, Headroom + initialClass: 'headroom', + unPinnedClass: 'headroom--unpinned', + pinnedClass: 'headroom--pinned' + }; + + return Headroom; + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/homescreensettings/homescreensettings.js b/src/bower_components/emby-webcomponents/homescreensettings/homescreensettings.js index 8a34eb9418..67d21a6f09 100644 --- a/src/bower_components/emby-webcomponents/homescreensettings/homescreensettings.js +++ b/src/bower_components/emby-webcomponents/homescreensettings/homescreensettings.js @@ -1,233 +1,543 @@ -define(["require", "apphost", "layoutManager", "focusManager", "globalize", "loading", "connectionManager", "homeSections", "dom", "events", "listViewStyle", "emby-select", "emby-checkbox"], function(require, appHost, layoutManager, focusManager, globalize, loading, connectionManager, homeSections, dom, events) { +define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loading', 'connectionManager', 'homeSections', 'dom', 'events', 'listViewStyle', 'emby-select', 'emby-checkbox'], function (require, appHost, layoutManager, focusManager, globalize, loading, connectionManager, homeSections, dom, events) { "use strict"; + var numConfigurableSections = 7; + function renderViews(page, user, result) { - var folderHtml = ""; - folderHtml += '
', folderHtml += result.map(function(i) { - var currentHtml = "", - id = "chkGroupFolder" + i.Id, - isChecked = -1 !== user.Configuration.GroupedFolders.indexOf(i.Id), - checkedHtml = isChecked ? ' checked="checked"' : ""; - return currentHtml += "" - }).join(""), folderHtml += "
", page.querySelector(".folderGroupList").innerHTML = folderHtml + + var folderHtml = ''; + + folderHtml += '
'; + folderHtml += result.map(function (i) { + + var currentHtml = ''; + + var id = 'chkGroupFolder' + i.Id; + + var isChecked = user.Configuration.GroupedFolders.indexOf(i.Id) !== -1; + + var checkedHtml = isChecked ? ' checked="checked"' : ''; + + currentHtml += ''; + + return currentHtml; + + }).join(''); + + folderHtml += '
'; + + page.querySelector('.folderGroupList').innerHTML = folderHtml; } function getLandingScreenOptions(type) { + var list = []; - return "movies" === type ? (list.push({ - name: globalize.translate("sharedcomponents#Movies"), - value: "movies", - isDefault: !0 - }), list.push({ - name: globalize.translate("sharedcomponents#Suggestions"), - value: "suggestions" - }), list.push({ - name: globalize.translate("sharedcomponents#Favorites"), - value: "favorites" - }), list.push({ - name: globalize.translate("sharedcomponents#Collections"), - value: "collections" - })) : "tvshows" === type ? (list.push({ - name: globalize.translate("sharedcomponents#Shows"), - value: "shows", - isDefault: !0 - }), list.push({ - name: globalize.translate("sharedcomponents#Suggestions"), - value: "suggestions" - }), list.push({ - name: globalize.translate("sharedcomponents#Latest"), - value: "latest" - }), list.push({ - name: globalize.translate("sharedcomponents#Favorites"), - value: "favorites" - })) : "music" === type ? (list.push({ - name: globalize.translate("sharedcomponents#Suggestions"), - value: "suggestions", - isDefault: !0 - }), list.push({ - name: globalize.translate("sharedcomponents#Albums"), - value: "albums" - }), list.push({ - name: globalize.translate("sharedcomponents#HeaderAlbumArtists"), - value: "albumartists" - }), list.push({ - name: globalize.translate("sharedcomponents#Artists"), - value: "artists" - }), list.push({ - name: globalize.translate("sharedcomponents#Playlists"), - value: "playlists" - }), list.push({ - name: globalize.translate("sharedcomponents#Genres"), - value: "genres" - })) : "livetv" === type && (list.push({ - name: globalize.translate("sharedcomponents#Suggestions"), - value: "suggestions", - isDefault: !0 - }), list.push({ - name: globalize.translate("sharedcomponents#Guide"), - value: "guide" - })), list + + if (type === 'movies') { + + list.push({ + name: globalize.translate('sharedcomponents#Movies'), + value: 'movies', + isDefault: true + }); + + list.push({ + name: globalize.translate('sharedcomponents#Suggestions'), + value: 'suggestions' + }); + + list.push({ + name: globalize.translate('sharedcomponents#Favorites'), + value: 'favorites' + }); + list.push({ + name: globalize.translate('sharedcomponents#Collections'), + value: 'collections' + }); + } + else if (type === 'tvshows') { + + list.push({ + name: globalize.translate('sharedcomponents#Shows'), + value: 'shows', + isDefault: true + }); + list.push({ + name: globalize.translate('sharedcomponents#Suggestions'), + value: 'suggestions' + }); + + list.push({ + name: globalize.translate('sharedcomponents#Latest'), + value: 'latest' + }); + list.push({ + name: globalize.translate('sharedcomponents#Favorites'), + value: 'favorites' + }); + } + else if (type === 'music') { + + list.push({ + name: globalize.translate('sharedcomponents#Suggestions'), + value: 'suggestions', + isDefault: true + }); + + list.push({ + name: globalize.translate('sharedcomponents#Albums'), + value: 'albums' + }); + + list.push({ + name: globalize.translate('sharedcomponents#HeaderAlbumArtists'), + value: 'albumartists' + }); + + list.push({ + name: globalize.translate('sharedcomponents#Artists'), + value: 'artists' + }); + + list.push({ + name: globalize.translate('sharedcomponents#Playlists'), + value: 'playlists' + }); + + list.push({ + name: globalize.translate('sharedcomponents#Genres'), + value: 'genres' + }); + } + else if (type === 'livetv') { + + list.push({ + name: globalize.translate('sharedcomponents#Suggestions'), + value: 'suggestions', + isDefault: true + }); + list.push({ + name: globalize.translate('sharedcomponents#Guide'), + value: 'guide' + }); + } + + return list; } function getLandingScreenOptionsHtml(type, userValue) { - return getLandingScreenOptions(type).map(function(o) { - var selected = userValue === o.value || o.isDefault && !userValue, - selectedHtml = selected ? " selected" : ""; - return '" - }).join("") + + return getLandingScreenOptions(type).map(function (o) { + + var selected = userValue === o.value || (o.isDefault && !userValue); + var selectedHtml = selected ? ' selected' : ''; + var optionValue = o.isDefault ? '' : o.value; + + return ''; + }).join(''); } function renderViewOrder(context, user, result) { - var html = "", - index = 0; - html += result.Items.map(function(view) { - var currentHtml = ""; - return currentHtml += '
', currentHtml += '', currentHtml += '
', currentHtml += "
", currentHtml += view.Name, currentHtml += "
", currentHtml += "
", currentHtml += '', currentHtml += '', currentHtml += "
", index++, currentHtml - }).join(""), context.querySelector(".viewOrderList").innerHTML = html + + var html = ''; + + var index = 0; + + html += result.Items.map(function (view) { + + var currentHtml = ''; + + currentHtml += '
'; + + currentHtml += ''; + + currentHtml += '
'; + + currentHtml += '
'; + currentHtml += view.Name; + currentHtml += '
'; + + currentHtml += '
'; + + currentHtml += ''; + currentHtml += ''; + + currentHtml += '
'; + + index++; + return currentHtml; + + }).join(''); + + context.querySelector('.viewOrderList').innerHTML = html; } function updateHomeSectionValues(context, userSettings) { + for (var i = 1; i <= 7; i++) { - var select = context.querySelector("#selectHomeSection" + i), - defaultValue = homeSections.getDefaultSection(i - 1), - option = select.querySelector("option[value=" + defaultValue + "]") || select.querySelector('option[value=""]'), - userValue = userSettings.get("homesection" + (i - 1)); - option.value = "", select.value = userValue !== defaultValue && userValue ? userValue : "" + + var select = context.querySelector('#selectHomeSection' + i); + var defaultValue = homeSections.getDefaultSection(i - 1); + + var option = select.querySelector('option[value=' + defaultValue + ']') || select.querySelector('option[value=""]'); + + var userValue = userSettings.get('homesection' + (i - 1)); + + option.value = ''; + + if (userValue === defaultValue || !userValue) { + select.value = ''; + } else { + select.value = userValue; + } } - context.querySelector(".selectTVHomeScreen").value = userSettings.get("tvhome") || "" + + context.querySelector('.selectTVHomeScreen').value = userSettings.get('tvhome') || ''; } function getPerLibrarySettingsHtml(item, user, userSettings, apiClient) { - var isChecked, html = ""; - if ("Channel" !== item.Type && "boxsets" !== item.CollectionType && "playlists" !== item.CollectionType || (isChecked = -1 === (user.Configuration.MyMediaExcludes || []).indexOf(item.Id), html += "
", html += "", html += "
"), -1 === ["playlists", "livetv", "boxsets", "channels"].indexOf(item.CollectionType || "") && (isChecked = -1 === user.Configuration.LatestItemsExcludes.indexOf(item.Id), html += '"), html && (html = '
' + html + "
"), "movies" === item.CollectionType || "tvshows" === item.CollectionType || "music" === item.CollectionType || "livetv" === item.CollectionType) { - var idForLanding = "livetv" === item.CollectionType ? item.CollectionType : item.Id; - html += '
', html += '", html += "
" + + var html = ''; + + var isChecked; + + if (item.Type === 'Channel' || item.CollectionType === 'boxsets' || item.CollectionType === 'playlists') { + isChecked = (user.Configuration.MyMediaExcludes || []).indexOf(item.Id) === -1; + html += '
'; + html += ''; + html += '
'; } + + var excludeFromLatest = ['playlists', 'livetv', 'boxsets', 'channels']; + if (excludeFromLatest.indexOf(item.CollectionType || '') === -1) { + + isChecked = user.Configuration.LatestItemsExcludes.indexOf(item.Id) === -1; + html += ''; + } + if (html) { - var prefix = ""; - prefix += '
', prefix += '

', prefix += item.Name, prefix += "

", html = prefix + html, html += "
" + + html = '
' + html + '
'; } - return html + + if (item.CollectionType === 'movies' || item.CollectionType === 'tvshows' || item.CollectionType === 'music' || item.CollectionType === 'livetv') { + + var idForLanding = item.CollectionType === 'livetv' ? item.CollectionType : item.Id; + html += '
'; + html += ''; + html += '
'; + } + + if (html) { + + var prefix = ''; + prefix += '
'; + + prefix += '

'; + prefix += item.Name; + prefix += '

'; + + html = prefix + html; + html += '
'; + } + + + return html; } function renderPerLibrarySettings(context, user, userViews, userSettings, apiClient) { - for (var elem = context.querySelector(".perLibrarySettings"), html = "", i = 0, length = userViews.length; i < length; i++) html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient); - elem.innerHTML = html + + var elem = context.querySelector('.perLibrarySettings'); + var html = ''; + + for (var i = 0, length = userViews.length; i < length; i++) { + + html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient); + } + + elem.innerHTML = html; } function loadForm(context, user, userSettings, apiClient) { - context.querySelector(".chkHidePlayedFromLatest").checked = user.Configuration.HidePlayedInLatest || !1, updateHomeSectionValues(context, userSettings); - var promise1 = apiClient.getUserViews({ - IncludeHidden: !0 - }, user.Id), - promise2 = apiClient.getJSON(apiClient.getUrl("Users/" + user.Id + "/GroupingOptions")); - Promise.all([promise1, promise2]).then(function(responses) { - renderViewOrder(context, user, responses[0]), renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient), renderViews(context, user, responses[1]), loading.hide() - }) + + context.querySelector('.chkHidePlayedFromLatest').checked = user.Configuration.HidePlayedInLatest || false; + + updateHomeSectionValues(context, userSettings); + + var promise1 = apiClient.getUserViews({ IncludeHidden: true }, user.Id); + var promise2 = apiClient.getJSON(apiClient.getUrl("Users/" + user.Id + "/GroupingOptions")); + + Promise.all([promise1, promise2]).then(function (responses) { + + renderViewOrder(context, user, responses[0]); + + renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient); + + renderViews(context, user, responses[1]); + + loading.hide(); + }); + } + + function getSibling(elem, type, className) { + + var sibling = elem[type]; + + while (sibling != null) { + if (sibling.classList.contains(className)) { + break; + } + } + + if (sibling != null) { + if (!sibling.classList.contains(className)) { + sibling = null; + } + } + + return sibling; } function onSectionOrderListClick(e) { - var target = dom.parentWithClass(e.target, "btnViewItemMove"); + + var target = dom.parentWithClass(e.target, 'btnViewItemMove'); + if (target) { - var viewItem = dom.parentWithClass(target, "viewItem"); + var viewItem = dom.parentWithClass(target, 'viewItem'); + if (viewItem) { - dom.parentWithClass(viewItem, "paperList"); - if (target.classList.contains("btnViewItemDown")) { + var ul = dom.parentWithClass(viewItem, 'paperList'); + + if (target.classList.contains('btnViewItemDown')) { + var next = viewItem.nextSibling; - next && (viewItem.parentNode.removeChild(viewItem), next.parentNode.insertBefore(viewItem, next.nextSibling)) + + if (next) { + viewItem.parentNode.removeChild(viewItem); + next.parentNode.insertBefore(viewItem, next.nextSibling); + } + } else { + var prev = viewItem.previousSibling; - prev && (viewItem.parentNode.removeChild(viewItem), prev.parentNode.insertBefore(viewItem, prev)) + + if (prev) { + viewItem.parentNode.removeChild(viewItem); + prev.parentNode.insertBefore(viewItem, prev); + } } } } } function getCheckboxItems(selector, context, isChecked) { - for (var inputs = context.querySelectorAll(selector), list = [], i = 0, length = inputs.length; i < length; i++) inputs[i].checked === isChecked && list.push(inputs[i]); - return list + + var inputs = context.querySelectorAll(selector); + var list = []; + + for (var i = 0, length = inputs.length; i < length; i++) { + + if (inputs[i].checked === isChecked) { + list.push(inputs[i]); + } + + } + + return list; } function saveUser(context, user, userSettingsInstance, apiClient) { - user.Configuration.HidePlayedInLatest = context.querySelector(".chkHidePlayedFromLatest").checked, user.Configuration.LatestItemsExcludes = getCheckboxItems(".chkIncludeInLatest", context, !1).map(function(i) { - return i.getAttribute("data-folderid") - }), user.Configuration.MyMediaExcludes = getCheckboxItems(".chkIncludeInMyMedia", context, !1).map(function(i) { - return i.getAttribute("data-folderid") - }), user.Configuration.GroupedFolders = getCheckboxItems(".chkGroupFolder", context, !0).map(function(i) { - return i.getAttribute("data-folderid") + + user.Configuration.HidePlayedInLatest = context.querySelector('.chkHidePlayedFromLatest').checked; + + user.Configuration.LatestItemsExcludes = getCheckboxItems(".chkIncludeInLatest", context, false).map(function (i) { + + return i.getAttribute('data-folderid'); }); - var i, length, viewItems = context.querySelectorAll(".viewItem"), - orderedViews = []; - for (i = 0, length = viewItems.length; i < length; i++) orderedViews.push(viewItems[i].getAttribute("data-viewid")); - user.Configuration.OrderedViews = orderedViews, userSettingsInstance.set("tvhome", context.querySelector(".selectTVHomeScreen").value), userSettingsInstance.set("homesection0", context.querySelector("#selectHomeSection1").value), userSettingsInstance.set("homesection1", context.querySelector("#selectHomeSection2").value), userSettingsInstance.set("homesection2", context.querySelector("#selectHomeSection3").value), userSettingsInstance.set("homesection3", context.querySelector("#selectHomeSection4").value), userSettingsInstance.set("homesection4", context.querySelector("#selectHomeSection5").value), userSettingsInstance.set("homesection5", context.querySelector("#selectHomeSection6").value), userSettingsInstance.set("homesection6", context.querySelector("#selectHomeSection7").value); - var selectLandings = context.querySelectorAll(".selectLanding"); + + user.Configuration.MyMediaExcludes = getCheckboxItems(".chkIncludeInMyMedia", context, false).map(function (i) { + + return i.getAttribute('data-folderid'); + }); + + user.Configuration.GroupedFolders = getCheckboxItems(".chkGroupFolder", context, true).map(function (i) { + + return i.getAttribute('data-folderid'); + }); + + var viewItems = context.querySelectorAll('.viewItem'); + var orderedViews = []; + var i, length; + for (i = 0, length = viewItems.length; i < length; i++) { + orderedViews.push(viewItems[i].getAttribute('data-viewid')); + } + + user.Configuration.OrderedViews = orderedViews; + + userSettingsInstance.set('tvhome', context.querySelector('.selectTVHomeScreen').value); + + userSettingsInstance.set('homesection0', context.querySelector('#selectHomeSection1').value); + userSettingsInstance.set('homesection1', context.querySelector('#selectHomeSection2').value); + userSettingsInstance.set('homesection2', context.querySelector('#selectHomeSection3').value); + userSettingsInstance.set('homesection3', context.querySelector('#selectHomeSection4').value); + userSettingsInstance.set('homesection4', context.querySelector('#selectHomeSection5').value); + userSettingsInstance.set('homesection5', context.querySelector('#selectHomeSection6').value); + userSettingsInstance.set('homesection6', context.querySelector('#selectHomeSection7').value); + + var selectLandings = context.querySelectorAll('.selectLanding'); for (i = 0, length = selectLandings.length; i < length; i++) { var selectLanding = selectLandings[i]; - userSettingsInstance.set("landing-" + selectLanding.getAttribute("data-folderid"), selectLanding.value) + userSettingsInstance.set('landing-' + selectLanding.getAttribute('data-folderid'), selectLanding.value); } - return apiClient.updateUserConfiguration(user.Id, user.Configuration) + + return apiClient.updateUserConfiguration(user.Id, user.Configuration); } function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) { - loading.show(), apiClient.getUser(userId).then(function(user) { - saveUser(context, user, userSettings, apiClient).then(function() { - loading.hide(), enableSaveConfirmation && require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#SettingsSaved")) - }), events.trigger(instance, "saved") - }, function() { - loading.hide() - }) - }) + + loading.show(); + + apiClient.getUser(userId).then(function (user) { + + saveUser(context, user, userSettings, apiClient).then(function () { + + loading.hide(); + if (enableSaveConfirmation) { + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#SettingsSaved')); + }); + } + + events.trigger(instance, 'saved'); + + }, function () { + loading.hide(); + }); + }); } function onSubmit(e) { - var self = this, - apiClient = connectionManager.getApiClient(self.options.serverId), - userId = self.options.userId, - userSettings = self.options.userSettings; - return userSettings.setUserInfo(userId, apiClient).then(function() { + + var self = this; + var apiClient = connectionManager.getApiClient(self.options.serverId); + var userId = self.options.userId; + var userSettings = self.options.userSettings; + + userSettings.setUserInfo(userId, apiClient).then(function () { + var enableSaveConfirmation = self.options.enableSaveConfirmation; - save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation) - }), e && e.preventDefault(), !1 + save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation); + }); + + // Disable default form submission + if (e) { + e.preventDefault(); + } + return false; } function onChange(e) { - var chkIncludeInMyMedia = dom.parentWithClass(e.target, "chkIncludeInMyMedia"); - if (chkIncludeInMyMedia) { - var section = dom.parentWithClass(chkIncludeInMyMedia, "verticalSection"), - fldIncludeInLatest = section.querySelector(".fldIncludeInLatest"); - fldIncludeInLatest && (chkIncludeInMyMedia.checked ? fldIncludeInLatest.classList.remove("hide") : fldIncludeInLatest.classList.add("hide")) + + var chkIncludeInMyMedia = dom.parentWithClass(e.target, 'chkIncludeInMyMedia'); + if (!chkIncludeInMyMedia) { + return; + } + + var section = dom.parentWithClass(chkIncludeInMyMedia, 'verticalSection'); + var fldIncludeInLatest = section.querySelector('.fldIncludeInLatest'); + if (fldIncludeInLatest) { + if (chkIncludeInMyMedia.checked) { + fldIncludeInLatest.classList.remove('hide'); + } else { + fldIncludeInLatest.classList.add('hide'); + } } } function embed(options, self) { - require(["text!./homescreensettings.template.html"], function(template) { - for (var i = 1; i <= numConfigurableSections; i++) template = template.replace("{section" + i + "label}", globalize.translate("sharedcomponents#LabelHomeScreenSectionValue", i)); - options.element.innerHTML = globalize.translateDocument(template, "sharedcomponents"), options.element.querySelector(".viewOrderList").addEventListener("click", onSectionOrderListClick), options.element.querySelector("form").addEventListener("submit", onSubmit.bind(self)), options.element.addEventListener("change", onChange), options.enableSaveButton && options.element.querySelector(".btnSave").classList.remove("hide"), layoutManager.tv ? options.element.querySelector(".selectTVHomeScreenContainer").classList.remove("hide") : options.element.querySelector(".selectTVHomeScreenContainer").classList.add("hide"), self.loadData(options.autoFocus) - }) + + require(['text!./homescreensettings.template.html'], function (template) { + + for (var i = 1; i <= numConfigurableSections; i++) { + template = template.replace('{section' + i + 'label}', globalize.translate('sharedcomponents#LabelHomeScreenSectionValue', i)); + } + + options.element.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + options.element.querySelector('.viewOrderList').addEventListener('click', onSectionOrderListClick); + options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self)); + options.element.addEventListener('change', onChange); + + if (options.enableSaveButton) { + options.element.querySelector('.btnSave').classList.remove('hide'); + } + + if (layoutManager.tv) { + options.element.querySelector('.selectTVHomeScreenContainer').classList.remove('hide'); + } else { + options.element.querySelector('.selectTVHomeScreenContainer').classList.add('hide'); + } + + self.loadData(options.autoFocus); + }); } function HomeScreenSettings(options) { - this.options = options, embed(options, this) + + this.options = options; + + embed(options, this); } - var numConfigurableSections = 7; - return HomeScreenSettings.prototype.loadData = function(autoFocus) { - var self = this, - context = self.options.element; + + HomeScreenSettings.prototype.loadData = function (autoFocus) { + + var self = this; + var context = self.options.element; + loading.show(); - var userId = self.options.userId, - apiClient = connectionManager.getApiClient(self.options.serverId), - userSettings = self.options.userSettings; - apiClient.getUser(userId).then(function(user) { - userSettings.setUserInfo(userId, apiClient).then(function() { - self.dataLoaded = !0, loadForm(context, user, userSettings, apiClient), autoFocus && focusManager.autoFocus(context) - }) - }) - }, HomeScreenSettings.prototype.submit = function() { - onSubmit.call(this) - }, HomeScreenSettings.prototype.destroy = function() { - this.options = null - }, HomeScreenSettings + + var userId = self.options.userId; + var apiClient = connectionManager.getApiClient(self.options.serverId); + var userSettings = self.options.userSettings; + + apiClient.getUser(userId).then(function (user) { + + userSettings.setUserInfo(userId, apiClient).then(function () { + + self.dataLoaded = true; + + loadForm(context, user, userSettings, apiClient); + + if (autoFocus) { + focusManager.autoFocus(context); + } + }); + }); + }; + + HomeScreenSettings.prototype.submit = function () { + onSubmit.call(this); + }; + + HomeScreenSettings.prototype.destroy = function () { + + this.options = null; + }; + + return HomeScreenSettings; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/homescreensettings/homescreensettingsdialog.js b/src/bower_components/emby-webcomponents/homescreensettings/homescreensettingsdialog.js index a21c16ec81..3962ccf239 100644 --- a/src/bower_components/emby-webcomponents/homescreensettings/homescreensettingsdialog.js +++ b/src/bower_components/emby-webcomponents/homescreensettings/homescreensettingsdialog.js @@ -1,47 +1,88 @@ -define(["dialogHelper", "layoutManager", "globalize", "require", "events", "homescreenSettings", "paper-icon-button-light", "css!./../formdialog"], function(dialogHelper, layoutManager, globalize, require, events, HomescreenSettings) { - "use strict"; +define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'events', 'homescreenSettings', 'paper-icon-button-light', 'css!./../formdialog'], function (dialogHelper, layoutManager, globalize, require, events, HomescreenSettings) { + 'use strict'; function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function show(options) { - return new Promise(function(resolve, reject) { - require(["text!./homescreensettingsdialog.template.html"], function(template) { + return new Promise(function (resolve, reject) { + + require(['text!./homescreensettingsdialog.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "medium-tall"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'medium-tall'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - var html = "", - submitted = !1; - html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0); + + dlg.classList.add('formDialog'); + + var html = ''; + var submitted = false; + + html += globalize.translateDocument(template, 'sharedcomponents'); + + dlg.innerHTML = html; + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + var homescreenSettingsInstance = new HomescreenSettings({ serverId: options.serverId, userId: options.userId, - element: dlg.querySelector(".settingsContent"), + element: dlg.querySelector('.settingsContent'), userSettings: options.userSettings, - enableSaveButton: !1, - enableSaveConfirmation: !1 + enableSaveButton: false, + enableSaveConfirmation: false }); - dialogHelper.open(dlg), dlg.addEventListener("close", function() { - layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), submitted ? resolve() : reject() - }), dlg.querySelector(".btnCancel").addEventListener("click", function(e) { - dialogHelper.close(dlg) - }), dlg.querySelector(".btnSave").addEventListener("click", function(e) { - submitted = !0, homescreenSettingsInstance.submit() - }), events.on(homescreenSettingsInstance, "saved", function() { - submitted = !0, dialogHelper.close(dlg) - }) - }) - }) + + dialogHelper.open(dlg); + + dlg.addEventListener('close', function () { + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + if (submitted) { + resolve(); + } else { + reject(); + } + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function (e) { + + dialogHelper.close(dlg); + }); + + dlg.querySelector('.btnSave').addEventListener('click', function (e) { + + submitted = true; + homescreenSettingsInstance.submit(); + }); + + events.on(homescreenSettingsInstance, 'saved', function () { + submitted = true; + dialogHelper.close(dlg); + }); + }); + }); } + return { show: show - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/homesections/homesections.css b/src/bower_components/emby-webcomponents/homesections/homesections.css index fac9ac5b64..7bb561ee01 100644 --- a/src/bower_components/emby-webcomponents/homesections/homesections.css +++ b/src/bower_components/emby-webcomponents/homesections/homesections.css @@ -1,10 +1,11 @@ -.homeLibraryButton { +.homeLibraryButton { min-width: 18%; - margin: .5em !important + margin: .5em !important; } -@media all and (max-width:50em) { +@media all and (max-width: 50em) { + .homeLibraryButton { - width: 46% !important + width: 46% !important; } } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/homesections/homesections.js b/src/bower_components/emby-webcomponents/homesections/homesections.js index bf464d2fc3..b5cf91ee54 100644 --- a/src/bower_components/emby-webcomponents/homesections/homesections.js +++ b/src/bower_components/emby-webcomponents/homesections/homesections.js @@ -1,121 +1,226 @@ -define(["connectionManager", "cardBuilder", "registrationServices", "appSettings", "dom", "apphost", "layoutManager", "imageLoader", "globalize", "itemShortcuts", "itemHelper", "appRouter", "emby-button", "paper-icon-button-light", "emby-itemscontainer", "emby-scroller", "emby-linkbutton", "css!./homesections"], function(connectionManager, cardBuilder, registrationServices, appSettings, dom, appHost, layoutManager, imageLoader, globalize, itemShortcuts, itemHelper, appRouter) { - "use strict"; +define(['connectionManager', 'cardBuilder', 'registrationServices', 'appSettings', 'dom', 'apphost', 'layoutManager', 'imageLoader', 'globalize', 'itemShortcuts', 'itemHelper', 'appRouter', 'emby-button', 'paper-icon-button-light', 'emby-itemscontainer', 'emby-scroller', 'emby-linkbutton', 'css!./homesections'], function (connectionManager, cardBuilder, registrationServices, appSettings, dom, appHost, layoutManager, imageLoader, globalize, itemShortcuts, itemHelper, appRouter) { + 'use strict'; function getDefaultSection(index) { + switch (index) { + case 0: - return "smalllibrarytiles"; + return 'smalllibrarytiles'; case 1: - return "resume"; + return 'resume'; case 2: - return "resumeaudio"; + return 'resumeaudio'; case 3: - return "livetv"; + return 'livetv'; case 4: - return "nextup"; + return 'nextup'; case 5: - return "latestmedia"; + return 'latestmedia'; case 6: - return "none"; + return 'none'; default: - return "" + return ''; } } function getAllSectionsToShow(userSettings, sectionCount) { - for (var sections = [], i = 0, length = sectionCount; i < length; i++) { - var section = userSettings.get("homesection" + i) || getDefaultSection(i); - "folders" === section && (section = getDefaultSection(0)), sections.push(section) + + var sections = []; + + for (var i = 0, length = sectionCount; i < length; i++) { + + var section = userSettings.get('homesection' + i) || getDefaultSection(i); + + if (section === 'folders') { + section = getDefaultSection(0); + } + + sections.push(section); } - return sections + + return sections; } function loadSections(elem, apiClient, user, userSettings) { - return getUserViews(apiClient, user.Id).then(function(userViews) { - var i, length, html = ""; - for (i = 0, length = 7; i < length; i++) html += '
'; - elem.innerHTML = html, elem.classList.add("homeSectionsContainer"); - var promises = [], - sections = getAllSectionsToShow(userSettings, 7); - for (i = 0, length = sections.length; i < length; i++) promises.push(loadSection(elem, apiClient, user, userSettings, userViews, sections, i)); - return Promise.all(promises).then(function() { - html = ""; - var style = "margin-top:4em;"; - return layoutManager.tv && (style += "padding: 0 7.5%;"), html += '", elem.insertAdjacentHTML("beforeend", html), resume(elem, { - refresh: !0, - returnPromise: !1 - }) - }) - }) + + return getUserViews(apiClient, user.Id).then(function (userViews) { + + var i, length; + var sectionCount = 7; + + var html = ''; + for (i = 0, length = sectionCount; i < length; i++) { + + html += '
'; + } + + elem.innerHTML = html; + elem.classList.add('homeSectionsContainer'); + + var promises = []; + var sections = getAllSectionsToShow(userSettings, sectionCount); + + for (i = 0, length = sections.length; i < length; i++) { + + promises.push(loadSection(elem, apiClient, user, userSettings, userViews, sections, i)); + } + + return Promise.all(promises).then(function () { + + html = ''; + + var style = 'margin-top:4em;'; + + if (layoutManager.tv) { + style += 'padding: 0 7.5%;'; + } + + html += ''; + + elem.insertAdjacentHTML('beforeend', html); + + return resume(elem, { + refresh: true, + returnPromise: false + }); + }); + }); } function destroySections(elem) { - var i, length, elems = elem.querySelectorAll(".itemsContainer"); - for (i = 0, length = elems.length; i < length; i++) elems[i].fetchData = null, elems[i].parentContainer = null, elems[i].getItemsHtml = null; - elem.innerHTML = "" + + var elems = elem.querySelectorAll('.itemsContainer'); + var i, length; + + for (i = 0, length = elems.length; i < length; i++) { + + elems[i].fetchData = null; + elems[i].parentContainer = null; + elems[i].getItemsHtml = null; + } + + elem.innerHTML = ''; } function pause(elem) { - var i, length, elems = elem.querySelectorAll(".itemsContainer"); - for (i = 0, length = elems.length; i < length; i++) elems[i].pause() + + var elems = elem.querySelectorAll('.itemsContainer'); + var i, length; + for (i = 0, length = elems.length; i < length; i++) { + + elems[i].pause(); + } } function resume(elem, options) { - var i, length, elems = elem.querySelectorAll(".itemsContainer"), - promises = []; - for (i = 0, length = elems.length; i < length; i++) promises.push(elems[i].resume(options)); - var promise = Promise.all(promises).then(function() { - elem.querySelector(".customizeSection").classList.remove("hide") + + var elems = elem.querySelectorAll('.itemsContainer'); + var i, length; + var promises = []; + + for (i = 0, length = elems.length; i < length; i++) { + promises.push(elems[i].resume(options)); + } + + var promise = Promise.all(promises).then(function () { + elem.querySelector('.customizeSection').classList.remove('hide'); }); - if (!options || !1 !== options.returnPromise) return promise + + if (!options || options.returnPromise !== false) { + return promise; + } } function loadSection(page, apiClient, user, userSettings, userViews, allSections, index) { - var section = allSections[index], - userId = user.Id, - elem = page.querySelector(".section" + index); - if ("latestmedia" === section) loadRecentlyAdded(elem, apiClient, user, userViews); - else { - if ("librarytiles" === section || "smalllibrarytiles" === section || "smalllibrarytiles-automobile" === section || "librarytiles-automobile" === section) return loadLibraryTiles(elem, apiClient, user, userSettings, "smallBackdrop", userViews, allSections); - if ("librarybuttons" === section) return loadlibraryButtons(elem, apiClient, user, userSettings, userViews); - if ("resume" === section) loadResumeVideo(elem, apiClient, userId); - else if ("resumeaudio" === section) loadResumeAudio(elem, apiClient, userId); - else if ("activerecordings" === section) loadLatestLiveTvRecordings(elem, !0, apiClient, userId); - else { - if ("nextup" !== section) return "onnow" === section || "livetv" === section ? loadOnNow(elem, apiClient, user) : (elem.innerHTML = "", Promise.resolve()); - loadNextUp(elem, apiClient, userId) - } + + var section = allSections[index]; + var userId = user.Id; + + var elem = page.querySelector('.section' + index); + + if (section === 'latestmedia') { + loadRecentlyAdded(elem, apiClient, user, userViews); } - return Promise.resolve() + else if (section === 'librarytiles' || section === 'smalllibrarytiles' || section === 'smalllibrarytiles-automobile' || section === 'librarytiles-automobile') { + return loadLibraryTiles(elem, apiClient, user, userSettings, 'smallBackdrop', userViews, allSections); + } + else if (section === 'librarybuttons') { + return loadlibraryButtons(elem, apiClient, user, userSettings, userViews, allSections); + } + else if (section === 'resume') { + loadResumeVideo(elem, apiClient, userId); + } + else if (section === 'resumeaudio') { + loadResumeAudio(elem, apiClient, userId); + } + else if (section === 'activerecordings') { + loadLatestLiveTvRecordings(elem, true, apiClient, userId); + } + else if (section === 'nextup') { + loadNextUp(elem, apiClient, userId); + } + else if (section === 'onnow' || section === 'livetv') { + return loadOnNow(elem, apiClient, user); + } + else { + + elem.innerHTML = ''; + + return Promise.resolve(); + } + return Promise.resolve(); } function getUserViews(apiClient, userId) { - return apiClient.getUserViews({}, userId || apiClient.getCurrentUserId()).then(function(result) { - return result.Items - }) + + return apiClient.getUserViews({}, userId || apiClient.getCurrentUserId()).then(function (result) { + + return result.Items; + }); } function enableScrollX() { - return !0 + return true; } function getSquareShape() { - return enableScrollX() ? "overflowSquare" : "square" + return enableScrollX() ? 'overflowSquare' : 'square'; } function getThumbShape() { - return enableScrollX() ? "overflowBackdrop" : "backdrop" + return enableScrollX() ? 'overflowBackdrop' : 'backdrop'; } function getPortraitShape() { - return enableScrollX() ? "autooverflow" : "auto" + return enableScrollX() ? 'autooverflow' : 'auto'; } function getLibraryButtonsHtml(items) { + var html = ""; - html += '
', html += '
', html += '

' + globalize.translate("sharedcomponents#HeaderMyMedia") + "

", layoutManager.tv || (html += ''), html += "
", html += '
'; + + html += '
'; + html += '
'; + html += '

' + globalize.translate('sharedcomponents#HeaderMyMedia') + '

'; + + if (!layoutManager.tv) { + html += ''; + } + + html += '
'; + + html += '
'; + + // "My Library" backgrounds for (var i = 0, length = items.length; i < length; i++) { - var icon, item = items[i]; + + var item = items[i]; + + var icon; + switch (item.CollectionType) { case "movies": icon = "local_movies"; @@ -127,6 +232,8 @@ define(["connectionManager", "cardBuilder", "registrationServices", "appSettings icon = "photo"; break; case "livetv": + icon = "live_tv"; + break; case "tvshows": icon = "live_tv"; break; @@ -137,476 +244,1031 @@ define(["connectionManager", "cardBuilder", "registrationServices", "appSettings icon = "local_movies"; break; case "homevideos": + icon = "video_library"; + break; case "musicvideos": icon = "video_library"; break; case "books": + icon = "folder"; + break; case "channels": + icon = "folder"; + break; case "playlists": + icon = "folder"; + break; default: - icon = "folder" + icon = "folder"; + break; } - html += '' + icon + "" + item.Name + "" + + html += '' + icon + '' + item.Name + ''; } - return html += "
", html += "
" + + html += '
'; + html += '
'; + + return html; } function loadlibraryButtons(elem, apiClient, user, userSettings, userViews) { - return Promise.all([getAppInfo(apiClient), getDownloadsSectionHtml(apiClient, user, userSettings)]).then(function(responses) { - var infoHtml = responses[0], - downloadsHtml = responses[1]; - elem.classList.remove("verticalSection"); + + return Promise.all([getAppInfo(apiClient), getDownloadsSectionHtml(apiClient, user, userSettings)]).then(function (responses) { + + var infoHtml = responses[0]; + var downloadsHtml = responses[1]; + + elem.classList.remove('verticalSection'); + var html = getLibraryButtonsHtml(userViews); - elem.innerHTML = html + downloadsHtml + infoHtml, bindHomeScreenSettingsIcon(elem, apiClient, user.Id, userSettings), infoHtml && bindAppInfoEvents(elem), imageLoader.lazyChildren(elem) - }) + + elem.innerHTML = html + downloadsHtml + infoHtml; + + bindHomeScreenSettingsIcon(elem, apiClient, user.Id, userSettings); + + if (infoHtml) { + bindAppInfoEvents(elem); + } + imageLoader.lazyChildren(elem); + }); } function bindAppInfoEvents(elem) { - elem.querySelector(".appInfoSection").addEventListener("click", function(e) { - dom.parentWithClass(e.target, "card") && registrationServices.showPremiereInfo() - }) + + elem.querySelector('.appInfoSection').addEventListener('click', function (e) { + + if (dom.parentWithClass(e.target, 'card')) { + registrationServices.showPremiereInfo(); + } + }); } + /** + * Returns a random integer between min (inclusive) and max (inclusive) + * Using Math.round() will give you a non-uniform distribution! + */ function getRandomInt(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min + return Math.floor(Math.random() * (max - min + 1)) + min; } function getAppInfo(apiClient) { - var cacheKey = "lastappinfopresent5", - lastDatePresented = parseInt(appSettings.get(cacheKey) || "0"); - return lastDatePresented ? (new Date).getTime() - lastDatePresented < 1728e5 ? Promise.resolve("") : registrationServices.validateFeature("dvr", { - showDialog: !1, - viewOnly: !0 - }).then(function() { - return appSettings.set(cacheKey, (new Date).getTime()), "" - }, function() { - appSettings.set(cacheKey, (new Date).getTime()); + + var frequency = 172800000; + + var cacheKey = 'lastappinfopresent5'; + var lastDatePresented = parseInt(appSettings.get(cacheKey) || '0'); + + // Don't show the first time, right after installation + if (!lastDatePresented) { + appSettings.set(cacheKey, new Date().getTime()); + return Promise.resolve(''); + } + + if ((new Date().getTime() - lastDatePresented) < frequency) { + return Promise.resolve(''); + } + + return registrationServices.validateFeature('dvr', { + + showDialog: false, + viewOnly: true + + }).then(function () { + + appSettings.set(cacheKey, new Date().getTime()); + return ''; + + }, function () { + + appSettings.set(cacheKey, new Date().getTime()); + var infos = [getPremiereInfo]; - return appHost.supports("otherapppromotions") && infos.push(getTheaterInfo), infos[getRandomInt(0, infos.length - 1)]() - }) : (appSettings.set(cacheKey, (new Date).getTime()), Promise.resolve("")) + + if (appHost.supports('otherapppromotions')) { + infos.push(getTheaterInfo); + } + + return infos[getRandomInt(0, infos.length - 1)](); + }); } function getCard(img, shape) { - shape = shape || "backdropCard"; - var html = '
'; - return html += '
', html += '
', html += "
", html += "
" + + shape = shape || 'backdropCard'; + var html = '
'; + + html += '
'; + + html += '
'; + + html += '
'; + + html += '
'; + + return html; } function getTheaterInfo() { - var html = ""; - html += '
', html += '
', html += '

Discover Jellyfin Theater

', html += '', html += "
"; - return html += '
', html += '

A beautiful app for your TV and large screen tablet. Jellyfin Theater runs on Windows, Xbox One, Raspberry Pi, Samsung Smart TVs, Sony PS4, Web Browsers, and more.

', html += '
', html += getCard("https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater1.png"), html += getCard("https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater2.png"), html += getCard("https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater3.png"), html += "
", html += "
", html += "
" + + var html = ''; + html += '
'; + html += '
'; + html += '

Discover Emby Theater

'; + html += ''; + html += '
'; + + var nameText = 'Emby Theater'; + html += '
'; + html += '

A beautiful app for your TV and large screen tablet. ' + nameText + ' runs on Windows, Xbox One, Raspberry Pi, Samsung Smart TVs, Sony PS4, Web Browsers, and more.

'; + html += '
'; + html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater1.png'); + html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater2.png'); + html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater3.png'); + html += '
'; + html += '
'; + html += '
'; + return html; } function getPremiereInfo() { - var html = ""; - return html += '
', html += '
', html += '

Discover Jellyfin Premiere

', html += '', html += "
", html += '
', html += '

Enjoy Jellyfin DVR, get free access to Jellyfin apps, and more.

', html += '
', html += getCard("https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater1.png"), html += getCard("https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater2.png"), html += getCard("https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater3.png"), html += "
", html += "
", html += "
" + + var html = ''; + html += '
'; + html += '
'; + html += '

Discover Emby Premiere

'; + html += ''; + html += '
'; + + html += '
'; + html += '

Enjoy Emby DVR, get free access to Emby apps, and more.

'; + html += '
'; + html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater1.png'); + html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater2.png'); + html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater3.png'); + html += '
'; + html += '
'; + html += '
'; + return html; } function getFetchLatestItemsFn(serverId, parentId, collectionType) { - return function() { - var apiClient = connectionManager.getApiClient(serverId), - limit = 16; - enableScrollX() ? "music" === collectionType && (limit = 30) : limit = "tvshows" === collectionType ? 5 : "music" === collectionType ? 9 : 8; + + return function () { + + var apiClient = connectionManager.getApiClient(serverId); + + var limit = 16; + + if (enableScrollX()) { + + if (collectionType === 'music') { + limit = 30; + } + } + else { + + if (collectionType === 'tvshows') { + limit = 5; + } else if (collectionType === 'music') { + limit = 9; + } else { + limit = 8; + } + } + var options = { + Limit: limit, Fields: "PrimaryImageAspectRatio,BasicSyncInfo", ImageTypeLimit: 1, EnableImageTypes: "Primary,Backdrop,Thumb", ParentId: parentId }; - return apiClient.getLatestItems(options) - } + + return apiClient.getLatestItems(options); + }; } function getLatestItemsHtmlFn(itemType, viewType) { - return function(items) { - var shape = "Channel" === itemType || "movies" === viewType ? getPortraitShape() : "music" === viewType ? getSquareShape() : getThumbShape(); + + return function (items) { + + var shape = itemType === 'Channel' || viewType === 'movies' ? + getPortraitShape() : + viewType === 'music' ? + getSquareShape() : + getThumbShape(); + + var cardLayout = false; + return cardBuilder.getCardsHtml({ items: items, shape: shape, - preferThumb: "movies" !== viewType && "Channel" !== itemType && "music" !== viewType ? "auto" : null, - showUnplayedIndicator: !1, - showChildCountIndicator: !0, - context: "home", - overlayText: !1, - centerText: !0, - overlayPlayButton: "photos" !== viewType, - allowBottomPadding: !enableScrollX() && !0, - cardLayout: !1, - showTitle: "photos" !== viewType, - showYear: "movies" === viewType || "tvshows" === viewType || !viewType, - showParentTitle: "music" === viewType || "tvshows" === viewType || !viewType || !1, + preferThumb: viewType !== 'movies' && itemType !== 'Channel' && viewType !== 'music' ? 'auto' : null, + showUnplayedIndicator: false, + showChildCountIndicator: true, + context: 'home', + overlayText: false, + centerText: !cardLayout, + overlayPlayButton: viewType !== 'photos', + allowBottomPadding: !enableScrollX() && !cardLayout, + cardLayout: cardLayout, + showTitle: viewType !== 'photos', + showYear: viewType === 'movies' || viewType === 'tvshows' || !viewType, + showParentTitle: viewType === 'music' || viewType === 'tvshows' || !viewType || (cardLayout && (viewType === 'tvshows')), lines: 2 - }) - } + }); + }; } function renderLatestSection(elem, apiClient, user, parent) { - var html = ""; - html += '
', layoutManager.tv ? html += '

' + globalize.translate("sharedcomponents#LatestFromLibrary", parent.Name) + "

" : (html += '', html += '

', html += globalize.translate("sharedcomponents#LatestFromLibrary", parent.Name), html += "

", html += '', html += "
"), html += "
", enableScrollX() ? html += '
' : html += '
', enableScrollX() && (html += "
"), html += "
", elem.innerHTML = html; - var itemsContainer = elem.querySelector(".itemsContainer"); - itemsContainer.fetchData = getFetchLatestItemsFn(apiClient.serverId(), parent.Id, parent.CollectionType), itemsContainer.getItemsHtml = getLatestItemsHtmlFn(parent.Type, parent.CollectionType), itemsContainer.parentContainer = elem + + var html = ''; + html += '
'; + if (!layoutManager.tv) { + + html += ''; + html += '

'; + html += globalize.translate('sharedcomponents#LatestFromLibrary', parent.Name); + html += '

'; + html += ''; + html += '
'; + + } else { + html += '

' + globalize.translate('sharedcomponents#LatestFromLibrary', parent.Name) + '

'; + } + html += '
'; + + if (enableScrollX()) { + html += '
'; + } else { + html += '
'; + } + + if (enableScrollX()) { + html += '
'; + } + html += '
'; + + elem.innerHTML = html; + + var itemsContainer = elem.querySelector('.itemsContainer'); + itemsContainer.fetchData = getFetchLatestItemsFn(apiClient.serverId(), parent.Id, parent.CollectionType); + itemsContainer.getItemsHtml = getLatestItemsHtmlFn(parent.Type, parent.CollectionType); + itemsContainer.parentContainer = elem; + } function loadRecentlyAdded(elem, apiClient, user, userViews) { - elem.classList.remove("verticalSection"); - for (var excludeViewTypes = ["playlists", "livetv", "boxsets", "channels"], i = 0, length = userViews.length; i < length; i++) { + + elem.classList.remove('verticalSection'); + + var excludeViewTypes = ['playlists', 'livetv', 'boxsets', 'channels']; + + for (var i = 0, length = userViews.length; i < length; i++) { + var item = userViews[i]; - if (-1 === user.Configuration.LatestItemsExcludes.indexOf(item.Id) && -1 === excludeViewTypes.indexOf(item.CollectionType || [])) { - var frag = document.createElement("div"); - frag.classList.add("verticalSection"), frag.classList.add("hide"), elem.appendChild(frag), renderLatestSection(frag, apiClient, user, item) + + if (user.Configuration.LatestItemsExcludes.indexOf(item.Id) !== -1) { + continue; } + + if (excludeViewTypes.indexOf(item.CollectionType || []) !== -1) { + continue; + } + + var frag = document.createElement('div'); + frag.classList.add('verticalSection'); + frag.classList.add('hide'); + elem.appendChild(frag); + + renderLatestSection(frag, apiClient, user, item); } } function getRequirePromise(deps) { - return new Promise(function(resolve, reject) { - require(deps, resolve) - }) + + return new Promise(function (resolve, reject) { + + require(deps, resolve); + }); } function showHomeScreenSettings(elem, options) { - return getRequirePromise(["homescreenSettingsDialog"]).then(function(homescreenSettingsDialog) { - return homescreenSettingsDialog.show(options).then(function() { - dom.parentWithClass(elem, "homeSectionsContainer").dispatchEvent(new CustomEvent("settingschange", { - cancelable: !1 - })) - }) - }) + return getRequirePromise(['homescreenSettingsDialog']).then(function (homescreenSettingsDialog) { + + return homescreenSettingsDialog.show(options).then(function () { + + dom.parentWithClass(elem, 'homeSectionsContainer').dispatchEvent(new CustomEvent('settingschange', { + cancelable: false + })); + }); + }); } function bindHomeScreenSettingsIcon(elem, apiClient, userId, userSettings) { - var btnHomeScreenSettings = elem.querySelector(".btnHomeScreenSettings"); - btnHomeScreenSettings && btnHomeScreenSettings.addEventListener("click", function() { + + var btnHomeScreenSettings = elem.querySelector('.btnHomeScreenSettings'); + if (!btnHomeScreenSettings) { + return; + } + + btnHomeScreenSettings.addEventListener('click', function () { showHomeScreenSettings(elem, { serverId: apiClient.serverId(), userId: userId, userSettings: userSettings - }) - }) + + }); + }); } function getDownloadsSectionHtml(apiClient, user, userSettings) { - return appHost.supports("sync") && user.Policy.EnableContentDownloading ? (apiClient.getLatestOfflineItems ? apiClient.getLatestOfflineItems({ + + if (!appHost.supports('sync') || !user.Policy.EnableContentDownloading) { + return Promise.resolve(''); + } + + var promise = apiClient.getLatestOfflineItems ? apiClient.getLatestOfflineItems({ + Limit: 20, - Filters: "IsNotFolder" - }) : Promise.resolve([])).then(function(items) { - var html = ""; - return html += '
', html += '
', layoutManager.tv ? html += '

' + globalize.translate("sharedcomponents#HeaderMyDownloads") + "

" : (html += '', html += '

', html += globalize.translate("sharedcomponents#HeaderMyDownloads"), html += "

", html += '', html += "
", html += ''), html += "
", html += '
', html += cardBuilder.getCardsHtml({ + Filters: 'IsNotFolder' + + }) : Promise.resolve([]); + + return promise.then(function (items) { + + var html = ''; + + html += '
'; + + html += '
'; + + if (!layoutManager.tv) { + + html += ''; + html += '

'; + html += globalize.translate('sharedcomponents#HeaderMyDownloads'); + html += '

'; + html += ''; + html += '
'; + + html += ''; + + } else { + html += '

' + globalize.translate('sharedcomponents#HeaderMyDownloads') + '

'; + } + html += '
'; + + html += '
'; + + var cardLayout = false; + + html += cardBuilder.getCardsHtml({ items: items, - preferThumb: "auto", - shape: "autooverflow", - overlayText: !1, - showTitle: !0, - showParentTitle: !0, - lazy: !0, - showDetailsMenu: !0, - overlayPlayButton: !0, - context: "home", - centerText: !0, - allowBottomPadding: !1, - cardLayout: !1, - showYear: !0, + preferThumb: 'auto', + shape: 'autooverflow', + overlayText: false, + showTitle: true, + showParentTitle: true, + lazy: true, + showDetailsMenu: true, + overlayPlayButton: true, + context: 'home', + centerText: !cardLayout, + allowBottomPadding: false, + cardLayout: cardLayout, + showYear: true, lines: 2 - }), html += "
", html += "
" - }) : Promise.resolve("") + }); + + html += '
'; + html += '
'; + + return html; + }); } function loadLibraryTiles(elem, apiClient, user, userSettings, shape, userViews, allSections) { - elem.classList.remove("verticalSection"); - var html = "", - scrollX = !layoutManager.desktop; - return userViews.length && (html += '
', html += '
', html += '

' + globalize.translate("sharedcomponents#HeaderMyMedia") + "

", layoutManager.tv || (html += ''), html += "
", html += scrollX ? '
' : '
', html += cardBuilder.getCardsHtml({ - items: userViews, - shape: scrollX ? "overflowSmallBackdrop" : shape, - showTitle: !0, - centerText: !0, - overlayText: !1, - lazy: !0, - transition: !1, - allowBottomPadding: !scrollX - }), scrollX && (html += "
"), html += "
", html += "
"), Promise.all([getAppInfo(apiClient), getDownloadsSectionHtml(apiClient, user, userSettings)]).then(function(responses) { - var infoHtml = responses[0], - downloadsHtml = responses[1]; - elem.innerHTML = html + downloadsHtml + infoHtml, bindHomeScreenSettingsIcon(elem, apiClient, user.Id, userSettings), infoHtml && bindAppInfoEvents(elem), imageLoader.lazyChildren(elem) - }) + + elem.classList.remove('verticalSection'); + + var html = ''; + + var scrollX = !layoutManager.desktop; + + if (userViews.length) { + + html += '
'; + + html += '
'; + html += '

' + globalize.translate('sharedcomponents#HeaderMyMedia') + '

'; + + if (!layoutManager.tv) { + html += ''; + } + + html += '
'; + + if (scrollX) { + html += '
'; + } else { + html += '
'; + } + + html += cardBuilder.getCardsHtml({ + items: userViews, + shape: scrollX ? 'overflowSmallBackdrop' : shape, + showTitle: true, + centerText: true, + overlayText: false, + lazy: true, + transition: false, + allowBottomPadding: !scrollX + }); + + if (scrollX) { + html += '
'; + } + html += '
'; + html += '
'; + } + + return Promise.all([getAppInfo(apiClient), getDownloadsSectionHtml(apiClient, user, userSettings)]).then(function (responses) { + + var infoHtml = responses[0]; + var downloadsHtml = responses[1]; + + elem.innerHTML = html + downloadsHtml + infoHtml; + + bindHomeScreenSettingsIcon(elem, apiClient, user.Id, userSettings); + + if (infoHtml) { + bindAppInfoEvents(elem); + } + + imageLoader.lazyChildren(elem); + }); } function getContinueWatchingFetchFn(serverId) { - return function() { - var limit, apiClient = connectionManager.getApiClient(serverId), - screenWidth = dom.getWindowSize().innerWidth; - enableScrollX() ? limit = 12 : (limit = screenWidth >= 1920 ? 8 : screenWidth >= 1600 ? 8 : screenWidth >= 1200 ? 9 : 6, limit = Math.min(limit, 5)); + + return function () { + + var apiClient = connectionManager.getApiClient(serverId); + + var screenWidth = dom.getWindowSize().innerWidth; + + var limit; + + if (enableScrollX()) { + + limit = 12; + + } else { + + limit = screenWidth >= 1920 ? 8 : (screenWidth >= 1600 ? 8 : (screenWidth >= 1200 ? 9 : 6)); + limit = Math.min(limit, 5); + } + var options = { + Limit: limit, - Recursive: !0, + Recursive: true, Fields: "PrimaryImageAspectRatio,BasicSyncInfo", ImageTypeLimit: 1, EnableImageTypes: "Primary,Backdrop,Thumb", - EnableTotalRecordCount: !1, - MediaTypes: "Video" + EnableTotalRecordCount: false, + MediaTypes: 'Video' }; - return apiClient.getResumableItems(apiClient.getCurrentUserId(), options) - } + + return apiClient.getResumableItems(apiClient.getCurrentUserId(), options); + }; } function getContinueWatchingItemsHtml(items) { + + var cardLayout = false; + return cardBuilder.getCardsHtml({ items: items, - preferThumb: !0, + preferThumb: true, shape: getThumbShape(), - overlayText: !1, - showTitle: !0, - showParentTitle: !0, - lazy: !0, - showDetailsMenu: !0, - overlayPlayButton: !0, - context: "home", - centerText: !0, - allowBottomPadding: !1, - cardLayout: !1, - showYear: !0, + overlayText: false, + showTitle: true, + showParentTitle: true, + lazy: true, + showDetailsMenu: true, + overlayPlayButton: true, + context: 'home', + centerText: !cardLayout, + allowBottomPadding: false, + cardLayout: cardLayout, + showYear: true, lines: 2 - }) + }); } function loadResumeVideo(elem, apiClient, userId) { - var html = ""; - html += '

' + globalize.translate("sharedcomponents#HeaderContinueWatching") + "

", enableScrollX() ? html += '
' : html += '
', enableScrollX() && (html += "
"), html += "
", elem.classList.add("hide"), elem.innerHTML = html; - var itemsContainer = elem.querySelector(".itemsContainer"); - itemsContainer.fetchData = getContinueWatchingFetchFn(apiClient.serverId()), itemsContainer.getItemsHtml = getContinueWatchingItemsHtml, itemsContainer.parentContainer = elem + + var html = ''; + html += '

' + globalize.translate('sharedcomponents#HeaderContinueWatching') + '

'; + + if (enableScrollX()) { + html += '
'; + } else { + html += '
'; + } + + if (enableScrollX()) { + html += '
'; + } + html += '
'; + + elem.classList.add('hide'); + elem.innerHTML = html; + + var itemsContainer = elem.querySelector('.itemsContainer'); + itemsContainer.fetchData = getContinueWatchingFetchFn(apiClient.serverId()); + itemsContainer.getItemsHtml = getContinueWatchingItemsHtml; + itemsContainer.parentContainer = elem; } function getContinueListeningFetchFn(serverId) { - return function() { - var limit, apiClient = connectionManager.getApiClient(serverId), - screenWidth = dom.getWindowSize().innerWidth; - enableScrollX() ? limit = 12 : (limit = screenWidth >= 1920 ? 8 : screenWidth >= 1600 ? 8 : screenWidth >= 1200 ? 9 : 6, limit = Math.min(limit, 5)); + + return function () { + + var apiClient = connectionManager.getApiClient(serverId); + + var screenWidth = dom.getWindowSize().innerWidth; + + var limit; + + if (enableScrollX()) { + + limit = 12; + + } else { + + limit = screenWidth >= 1920 ? 8 : (screenWidth >= 1600 ? 8 : (screenWidth >= 1200 ? 9 : 6)); + limit = Math.min(limit, 5); + } + var options = { + Limit: limit, - Recursive: !0, + Recursive: true, Fields: "PrimaryImageAspectRatio,BasicSyncInfo", ImageTypeLimit: 1, EnableImageTypes: "Primary,Backdrop,Thumb", - EnableTotalRecordCount: !1, - MediaTypes: "Audio" + EnableTotalRecordCount: false, + MediaTypes: 'Audio' }; - return apiClient.getResumableItems(apiClient.getCurrentUserId(), options) - } + + return apiClient.getResumableItems(apiClient.getCurrentUserId(), options); + }; } function getContinueListeningItemsHtml(items) { + + var cardLayout = false; + return cardBuilder.getCardsHtml({ items: items, - preferThumb: !0, + preferThumb: true, shape: getThumbShape(), - overlayText: !1, - showTitle: !0, - showParentTitle: !0, - lazy: !0, - showDetailsMenu: !0, - overlayPlayButton: !0, - context: "home", - centerText: !0, - allowBottomPadding: !1, - cardLayout: !1, - showYear: !0, + overlayText: false, + showTitle: true, + showParentTitle: true, + lazy: true, + showDetailsMenu: true, + overlayPlayButton: true, + context: 'home', + centerText: !cardLayout, + allowBottomPadding: false, + cardLayout: cardLayout, + showYear: true, lines: 2 - }) + }); } function loadResumeAudio(elem, apiClient, userId) { - var html = ""; - html += '

' + globalize.translate("sharedcomponents#HeaderContinueWatching") + "

", enableScrollX() ? html += '
' : html += '
', enableScrollX() && (html += "
"), html += "
", elem.classList.add("hide"), elem.innerHTML = html; - var itemsContainer = elem.querySelector(".itemsContainer"); - itemsContainer.fetchData = getContinueListeningFetchFn(apiClient.serverId()), itemsContainer.getItemsHtml = getContinueListeningItemsHtml, itemsContainer.parentContainer = elem + + var html = ''; + html += '

' + globalize.translate('sharedcomponents#HeaderContinueWatching') + '

'; + + if (enableScrollX()) { + html += '
'; + } else { + html += '
'; + } + + if (enableScrollX()) { + html += '
'; + } + html += '
'; + + elem.classList.add('hide'); + elem.innerHTML = html; + + var itemsContainer = elem.querySelector('.itemsContainer'); + itemsContainer.fetchData = getContinueListeningFetchFn(apiClient.serverId()); + itemsContainer.getItemsHtml = getContinueListeningItemsHtml; + itemsContainer.parentContainer = elem; } function bindUnlockClick(elem) { - var btnUnlock = elem.querySelector(".btnUnlock"); - btnUnlock && btnUnlock.addEventListener("click", function(e) { - registrationServices.validateFeature("livetv", { - viewOnly: !0 - }).then(function() { - dom.parentWithClass(elem, "homeSectionsContainer").dispatchEvent(new CustomEvent("settingschange", { - cancelable: !1 - })) - }) - }) - } - function getOnNowFetchFn(serverId) { - return function() { - var apiClient = connectionManager.getApiClient(serverId); - return apiClient.getLiveTvRecommendedPrograms({ - userId: apiClient.getCurrentUserId(), - IsAiring: !0, - limit: 24, - ImageTypeLimit: 1, - EnableImageTypes: "Primary,Thumb,Backdrop", - EnableTotalRecordCount: !1, - Fields: "ChannelInfo,PrimaryImageAspectRatio" - }) + var btnUnlock = elem.querySelector('.btnUnlock'); + if (btnUnlock) { + btnUnlock.addEventListener('click', function (e) { + + registrationServices.validateFeature('livetv', { + + viewOnly: true + + }).then(function () { + + dom.parentWithClass(elem, 'homeSectionsContainer').dispatchEvent(new CustomEvent('settingschange', { + cancelable: false + })); + }); + }); } } + function getOnNowFetchFn(serverId) { + + return function () { + + var apiClient = connectionManager.getApiClient(serverId); + + return apiClient.getLiveTvRecommendedPrograms({ + + userId: apiClient.getCurrentUserId(), + IsAiring: true, + limit: 24, + ImageTypeLimit: 1, + EnableImageTypes: "Primary,Thumb,Backdrop", + EnableTotalRecordCount: false, + Fields: "ChannelInfo,PrimaryImageAspectRatio" + + }); + }; + } + function getOnNowItemsHtml(items) { + + var cardLayout = false; + return cardBuilder.getCardsHtml({ items: items, - preferThumb: "auto", - inheritThumb: !1, - shape: enableScrollX() ? "autooverflow" : "auto", - showParentTitleOrTitle: !0, - showTitle: !0, - centerText: !0, - coverImage: !0, - overlayText: !1, + preferThumb: 'auto', + inheritThumb: false, + shape: (enableScrollX() ? 'autooverflow' : 'auto'), + showParentTitleOrTitle: true, + showTitle: true, + centerText: true, + coverImage: true, + overlayText: false, allowBottomPadding: !enableScrollX(), - showAirTime: !0, - showChannelName: !1, - showAirDateTime: !1, - showAirEndTime: !0, + showAirTime: true, + showChannelName: false, + showAirDateTime: false, + showAirEndTime: true, defaultShape: getThumbShape(), lines: 3, - overlayPlayButton: !0 - }) + overlayPlayButton: true + }); } function loadOnNow(elem, apiClient, user) { - if (!user.Policy.EnableLiveTvAccess) return Promise.resolve(); + + if (!user.Policy.EnableLiveTvAccess) { + return Promise.resolve(); + } + var promises = []; - promises.push(registrationServices.validateFeature("livetv", { - viewOnly: !0, - showDialog: !1 - }).then(function() { - return !0 - }, function() { - return !1 - })); - user.Id; - return promises.push(apiClient.getLiveTvRecommendedPrograms({ + + promises.push(registrationServices.validateFeature('livetv', + { + viewOnly: true, + showDialog: false + }).then(function () { + return true; + }, function () { + return false; + })); + + var userId = user.Id; + + promises.push(apiClient.getLiveTvRecommendedPrograms({ + userId: apiClient.getCurrentUserId(), - IsAiring: !0, + IsAiring: true, limit: 1, ImageTypeLimit: 1, EnableImageTypes: "Primary,Thumb,Backdrop", - EnableTotalRecordCount: !1, + EnableTotalRecordCount: false, Fields: "ChannelInfo,PrimaryImageAspectRatio" - })), Promise.all(promises).then(function(responses) { - var registered = responses[0], - result = responses[1], - html = ""; + + })); + + return Promise.all(promises).then(function (responses) { + + var registered = responses[0]; + var result = responses[1]; + var html = ''; + if (result.Items.length && registered) { - elem.classList.remove("padded-left"), elem.classList.remove("padded-right"), elem.classList.remove("padded-bottom"), elem.classList.remove("verticalSection"), html += '
', html += '
', html += '

' + globalize.translate("sharedcomponents#LiveTV") + "

", html += "
", enableScrollX() ? (html += '
', html += '", html += '
', html += '
', layoutManager.tv ? html += '

' + globalize.translate("sharedcomponents#HeaderOnNow") + "

" : (html += '', html += '

', html += globalize.translate("sharedcomponents#HeaderOnNow"), html += "

", html += '', html += "
"), html += "
", enableScrollX() ? html += '
' : html += '
', enableScrollX() && (html += "
"), html += "
", html += "
", elem.innerHTML = html; - var itemsContainer = elem.querySelector(".itemsContainer"); - itemsContainer.parentContainer = elem, itemsContainer.fetchData = getOnNowFetchFn(apiClient.serverId()), itemsContainer.getItemsHtml = getOnNowItemsHtml - } else result.Items.length && !registered && (elem.classList.add("padded-left"), elem.classList.add("padded-right"), elem.classList.add("padded-bottom"), html += '

' + globalize.translate("sharedcomponents#LiveTvRequiresUnlock") + "

", html += '", elem.innerHTML = html); - bindUnlockClick(elem) - }) + section: 'dvrschedule' + + }) + '" class="raised">' + globalize.translate('sharedcomponents#Schedule') + ''; + + html += '
'; + + if (enableScrollX()) { + html += '
'; + } + + html += '
'; + html += '
'; + + html += '
'; + html += '
'; + + if (!layoutManager.tv) { + + html += ''; + html += '

'; + html += globalize.translate('sharedcomponents#HeaderOnNow'); + html += '

'; + html += ''; + html += '
'; + + } else { + html += '

' + globalize.translate('sharedcomponents#HeaderOnNow') + '

'; + } + html += '
'; + + if (enableScrollX()) { + html += '
'; + } else { + html += '
'; + } + + if (enableScrollX()) { + html += '
'; + } + + html += '
'; + html += '
'; + + elem.innerHTML = html; + + var itemsContainer = elem.querySelector('.itemsContainer'); + itemsContainer.parentContainer = elem; + itemsContainer.fetchData = getOnNowFetchFn(apiClient.serverId()); + itemsContainer.getItemsHtml = getOnNowItemsHtml; + + } else if (result.Items.length && !registered) { + + elem.classList.add('padded-left'); + elem.classList.add('padded-right'); + elem.classList.add('padded-bottom'); + + html += '

' + globalize.translate('sharedcomponents#LiveTvRequiresUnlock') + '

'; + html += ''; + + elem.innerHTML = html; + } + + bindUnlockClick(elem); + }); } function getNextUpFetchFn(serverId) { - return function() { + + return function () { + var apiClient = connectionManager.getApiClient(serverId); + return apiClient.getNextUpEpisodes({ + Limit: enableScrollX() ? 24 : 15, Fields: "PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo", UserId: apiClient.getCurrentUserId(), ImageTypeLimit: 1, EnableImageTypes: "Primary,Backdrop,Banner,Thumb", - EnableTotalRecordCount: !1 - }) - } + EnableTotalRecordCount: false + }); + }; } function getNextUpItemsHtml(items) { + + var cardLayout = false; + return cardBuilder.getCardsHtml({ items: items, - preferThumb: !0, + preferThumb: true, shape: getThumbShape(), - overlayText: !1, - showTitle: !0, - showParentTitle: !0, - lazy: !0, - overlayPlayButton: !0, - context: "home", - centerText: !0, + overlayText: false, + showTitle: true, + showParentTitle: true, + lazy: true, + overlayPlayButton: true, + context: 'home', + centerText: !cardLayout, allowBottomPadding: !enableScrollX(), - cardLayout: !1 - }) + cardLayout: cardLayout + }); } function loadNextUp(elem, apiClient, userId) { - var html = ""; - html += '
', layoutManager.tv ? html += '

' + globalize.translate("sharedcomponents#HeaderNextUp") + "

" : (html += '', html += '

', html += globalize.translate("sharedcomponents#HeaderNextUp"), html += "

", html += '', html += "
"), html += "
", enableScrollX() ? html += '
' : html += '
', enableScrollX() && (html += "
"), html += "
", elem.classList.add("hide"), elem.innerHTML = html; - var itemsContainer = elem.querySelector(".itemsContainer"); - itemsContainer.fetchData = getNextUpFetchFn(apiClient.serverId()), itemsContainer.getItemsHtml = getNextUpItemsHtml, itemsContainer.parentContainer = elem + + var html = ''; + html += '
'; + if (!layoutManager.tv) { + + html += ''; + html += '

'; + html += globalize.translate('sharedcomponents#HeaderNextUp'); + html += '

'; + html += ''; + html += '
'; + + } else { + html += '

' + globalize.translate('sharedcomponents#HeaderNextUp') + '

'; + } + html += '
'; + + if (enableScrollX()) { + html += '
'; + } else { + html += '
'; + } + + if (enableScrollX()) { + html += '
'; + } + + html += '
'; + + elem.classList.add('hide'); + elem.innerHTML = html; + + var itemsContainer = elem.querySelector('.itemsContainer'); + itemsContainer.fetchData = getNextUpFetchFn(apiClient.serverId()); + itemsContainer.getItemsHtml = getNextUpItemsHtml; + itemsContainer.parentContainer = elem; } function getLatestRecordingsFetchFn(serverId, activeRecordingsOnly) { - return function() { + + return function () { + var apiClient = connectionManager.getApiClient(serverId); + return apiClient.getLiveTvRecordings({ + userId: apiClient.getCurrentUserId(), Limit: enableScrollX() ? 12 : 5, Fields: "PrimaryImageAspectRatio,BasicSyncInfo", - EnableTotalRecordCount: !1, - IsLibraryItem: !!activeRecordingsOnly && null, - IsInProgress: !!activeRecordingsOnly || null - }) - } + EnableTotalRecordCount: false, + IsLibraryItem: activeRecordingsOnly ? null : false, + IsInProgress: activeRecordingsOnly ? true : null + + }); + }; } function getLatestRecordingItemsHtml(activeRecordingsOnly) { - return function(items) { + + return function (items) { + var cardLayout = false; + return cardBuilder.getCardsHtml({ items: items, - shape: enableScrollX() ? "autooverflow" : "auto", - showTitle: !0, - showParentTitle: !0, - coverImage: !0, - lazy: !0, - showDetailsMenu: !0, - centerText: !0, - overlayText: !1, - showYear: !0, + shape: enableScrollX() ? 'autooverflow' : 'auto', + showTitle: true, + showParentTitle: true, + coverImage: true, + lazy: true, + showDetailsMenu: true, + centerText: true, + overlayText: false, + showYear: true, lines: 2, overlayPlayButton: !activeRecordingsOnly, allowBottomPadding: !enableScrollX(), - preferThumb: !0, - cardLayout: !1, + preferThumb: true, + cardLayout: false, overlayMoreButton: activeRecordingsOnly, - action: activeRecordingsOnly ? "none" : null, + action: activeRecordingsOnly ? 'none' : null, centerPlayButton: activeRecordingsOnly - }) - } + }); + }; } function loadLatestLiveTvRecordings(elem, activeRecordingsOnly, apiClient, userId) { - var title = activeRecordingsOnly ? globalize.translate("sharedcomponents#HeaderActiveRecordings") : globalize.translate("sharedcomponents#HeaderLatestRecordings"), - html = ""; - html += '
', html += '

' + title + "

", layoutManager.tv, html += "
", enableScrollX() ? html += '
' : html += '
', enableScrollX() && (html += "
"), html += "
", elem.classList.add("hide"), elem.innerHTML = html; - var itemsContainer = elem.querySelector(".itemsContainer"); - itemsContainer.fetchData = getLatestRecordingsFetchFn(apiClient.serverId(), activeRecordingsOnly), itemsContainer.getItemsHtml = getLatestRecordingItemsHtml(activeRecordingsOnly), itemsContainer.parentContainer = elem + + var title = activeRecordingsOnly ? + globalize.translate('sharedcomponents#HeaderActiveRecordings') : + globalize.translate('sharedcomponents#HeaderLatestRecordings'); + + var html = ''; + + html += '
'; + html += '

' + title + '

'; + if (!layoutManager.tv) { + //html += ''; + //html += ''; + } + html += '
'; + + if (enableScrollX()) { + html += '
'; + } else { + html += '
'; + } + + if (enableScrollX()) { + html += '
'; + } + + html += '
'; + + elem.classList.add('hide'); + elem.innerHTML = html; + + var itemsContainer = elem.querySelector('.itemsContainer'); + itemsContainer.fetchData = getLatestRecordingsFetchFn(apiClient.serverId(), activeRecordingsOnly); + itemsContainer.getItemsHtml = getLatestRecordingItemsHtml(activeRecordingsOnly); + itemsContainer.parentContainer = elem; } + return { loadLibraryTiles: loadLibraryTiles, getDefaultSection: getDefaultSection, @@ -614,5 +1276,5 @@ define(["connectionManager", "cardBuilder", "registrationServices", "appSettings destroySections: destroySections, pause: pause, resume: resume - } -}); + }; +}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/htmlaudioplayer/plugin.js b/src/bower_components/emby-webcomponents/htmlaudioplayer/plugin.js index e36ac4d469..daf22790a6 100644 --- a/src/bower_components/emby-webcomponents/htmlaudioplayer/plugin.js +++ b/src/bower_components/emby-webcomponents/htmlaudioplayer/plugin.js @@ -1,218 +1,515 @@ -define(["events", "browser", "require", "apphost", "appSettings", "htmlMediaHelper"], function(events, browser, require, appHost, appSettings, htmlMediaHelper) { +define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelper'], function (events, browser, require, appHost, appSettings, htmlMediaHelper) { "use strict"; function getDefaultProfile() { - return new Promise(function(resolve, reject) { - require(["browserdeviceprofile"], function(profileBuilder) { - resolve(profileBuilder({})) - }) - }) + + return new Promise(function (resolve, reject) { + + require(['browserdeviceprofile'], function (profileBuilder) { + + resolve(profileBuilder({})); + }); + }); } + var fadeTimeout; function fade(instance, elem, startingVolume) { - instance._isFadingOut = !0; - var newVolume = Math.max(0, startingVolume - .15); - return console.log("fading volume to " + newVolume), elem.volume = newVolume, newVolume <= 0 ? (instance._isFadingOut = !1, Promise.resolve()) : new Promise(function(resolve, reject) { - cancelFadeTimeout(), fadeTimeout = setTimeout(function() { - fade(instance, elem, newVolume).then(resolve, reject) - }, 100) - }) + + instance._isFadingOut = true; + + // Need to record the starting volume on each pass rather than querying elem.volume + // This is due to iOS safari not allowing volume changes and always returning the system volume value + + var newVolume = Math.max(0, startingVolume - 0.15); + console.log('fading volume to ' + newVolume); + elem.volume = newVolume; + + if (newVolume <= 0) { + + instance._isFadingOut = false; + return Promise.resolve(); + } + + return new Promise(function (resolve, reject) { + + cancelFadeTimeout(); + + fadeTimeout = setTimeout(function () { + + fade(instance, elem, newVolume).then(resolve, reject); + }, 100); + }); } function cancelFadeTimeout() { var timeout = fadeTimeout; - timeout && (clearTimeout(timeout), fadeTimeout = null) + if (timeout) { + clearTimeout(timeout); + fadeTimeout = null; + } } function supportsFade() { - return !browser.tv + + if (browser.tv) { + // Not working on tizen. + // We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive + return false; + } + + return true; } function requireHlsPlayer(callback) { - require(["hlsjs"], function(hls) { - window.Hls = hls, callback() - }) + require(['hlsjs'], function (hls) { + window.Hls = hls; + callback(); + }); } function enableHlsPlayer(url, item, mediaSource, mediaType) { - return htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType) ? -1 !== url.indexOf(".m3u8") ? Promise.resolve() : new Promise(function(resolve, reject) { - require(["fetchHelper"], function(fetchHelper) { + + if (!htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType)) { + + return Promise.reject(); + } + + if (url.indexOf('.m3u8') !== -1) { + return Promise.resolve(); + } + + // issue head request to get content type + return new Promise(function (resolve, reject) { + + require(['fetchHelper'], function (fetchHelper) { fetchHelper.ajax({ url: url, - type: "HEAD" - }).then(function(response) { - "application/x-mpegurl" === (response.headers.get("Content-Type") || "").toLowerCase() ? resolve() : reject() - }, reject) - }) - }) : Promise.reject() + type: 'HEAD' + }).then(function (response) { + + var contentType = (response.headers.get('Content-Type') || '').toLowerCase(); + if (contentType === 'application/x-mpegurl') { + resolve(); + } else { + reject(); + } + + }, reject); + }); + }); } function HtmlAudioPlayer() { + + var self = this; + + self.name = 'Html Audio Player'; + self.type = 'mediaplayer'; + self.id = 'htmlaudioplayer'; + + // Let any players created by plugins take priority + self.priority = 1; + + self.play = function (options) { + + self._started = false; + self._timeUpdated = false; + + self._currentTime = null; + + var elem = createMediaElement(options); + + return setCurrentSrc(elem, options); + }; + function setCurrentSrc(elem, options) { - elem.removeEventListener("error", onError), unBindEvents(elem), bindEvents(elem); + + elem.removeEventListener('error', onError); + + unBindEvents(elem); + bindEvents(elem); + var val = options.url; - console.log("playing url: " + val); - var seconds = (options.playerStartPositionTicks || 0) / 1e7; - seconds && (val += "#t=" + seconds), htmlMediaHelper.destroyHlsPlayer(self), self._currentPlayOptions = options; + console.log('playing url: ' + val); + + // Convert to seconds + var seconds = (options.playerStartPositionTicks || 0) / 10000000; + if (seconds) { + val += '#t=' + seconds; + } + + htmlMediaHelper.destroyHlsPlayer(self); + + self._currentPlayOptions = options; + var crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource); - return crossOrigin && (elem.crossOrigin = crossOrigin), enableHlsPlayer(val, options.item, options.mediaSource, "Audio").then(function() { - return new Promise(function(resolve, reject) { - requireHlsPlayer(function() { + if (crossOrigin) { + elem.crossOrigin = crossOrigin; + } + + return enableHlsPlayer(val, options.item, options.mediaSource, 'Audio').then(function () { + + return new Promise(function (resolve, reject) { + + requireHlsPlayer(function () { var hls = new Hls({ - manifestLoadingTimeOut: 2e4 + manifestLoadingTimeOut: 20000 + //appendErrorMaxRetry: 6, + //debug: true }); - hls.loadSource(val), hls.attachMedia(elem), htmlMediaHelper.bindEventsToHlsPlayer(self, hls, elem, onError, resolve, reject), self._hlsPlayer = hls, self._currentSrc = val - }) - }) - }, function() { - return elem.autoplay = !0, htmlMediaHelper.applySrc(elem, val, options).then(function() { - return self._currentSrc = val, htmlMediaHelper.playWithPromise(elem, onError) - }) - }) + hls.loadSource(val); + hls.attachMedia(elem); + + htmlMediaHelper.bindEventsToHlsPlayer(self, hls, elem, onError, resolve, reject); + + self._hlsPlayer = hls; + + self._currentSrc = val; + }); + }); + + + }, function () { + + elem.autoplay = true; + + return htmlMediaHelper.applySrc(elem, val, options).then(function () { + + self._currentSrc = val; + + return htmlMediaHelper.playWithPromise(elem, onError); + }); + }); } function bindEvents(elem) { - elem.addEventListener("timeupdate", onTimeUpdate), elem.addEventListener("ended", onEnded), elem.addEventListener("volumechange", onVolumeChange), elem.addEventListener("pause", onPause), elem.addEventListener("playing", onPlaying), elem.addEventListener("play", onPlay) + elem.addEventListener('timeupdate', onTimeUpdate); + elem.addEventListener('ended', onEnded); + elem.addEventListener('volumechange', onVolumeChange); + elem.addEventListener('pause', onPause); + elem.addEventListener('playing', onPlaying); + elem.addEventListener('play', onPlay); } function unBindEvents(elem) { - elem.removeEventListener("timeupdate", onTimeUpdate), elem.removeEventListener("ended", onEnded), elem.removeEventListener("volumechange", onVolumeChange), elem.removeEventListener("pause", onPause), elem.removeEventListener("playing", onPlaying), elem.removeEventListener("play", onPlay) + elem.removeEventListener('timeupdate', onTimeUpdate); + elem.removeEventListener('ended', onEnded); + elem.removeEventListener('volumechange', onVolumeChange); + elem.removeEventListener('pause', onPause); + elem.removeEventListener('playing', onPlaying); + elem.removeEventListener('play', onPlay); } - function createMediaElement() { + self.stop = function (destroyPlayer) { + + cancelFadeTimeout(); + var elem = self._mediaElement; - return elem || (elem = document.querySelector(".mediaPlayerAudio"), elem || (elem = document.createElement("audio"), elem.classList.add("mediaPlayerAudio"), elem.classList.add("hide"), document.body.appendChild(elem)), elem.volume = htmlMediaHelper.getSavedVolume(), self._mediaElement = elem, elem) + var src = self._currentSrc; + + if (elem && src) { + + if (!destroyPlayer || !supportsFade()) { + + elem.pause(); + + htmlMediaHelper.onEndedInternal(self, elem, onError); + + if (destroyPlayer) { + self.destroy(); + } + return Promise.resolve(); + } + + var originalVolume = elem.volume; + + return fade(self, elem, elem.volume).then(function () { + + elem.pause(); + elem.volume = originalVolume; + + htmlMediaHelper.onEndedInternal(self, elem, onError); + + if (destroyPlayer) { + self.destroy(); + } + }); + } + return Promise.resolve(); + }; + + self.destroy = function () { + unBindEvents(self._mediaElement); + }; + + function createMediaElement() { + + var elem = self._mediaElement; + + if (elem) { + return elem; + } + + elem = document.querySelector('.mediaPlayerAudio'); + + if (!elem) { + elem = document.createElement('audio'); + elem.classList.add('mediaPlayerAudio'); + elem.classList.add('hide'); + + document.body.appendChild(elem); + } + + elem.volume = htmlMediaHelper.getSavedVolume(); + + self._mediaElement = elem; + + return elem; } function onEnded() { - htmlMediaHelper.onEndedInternal(self, this, onError) + + htmlMediaHelper.onEndedInternal(self, this, onError); } function onTimeUpdate() { + + // Get the player position + the transcoding offset var time = this.currentTime; - self._isFadingOut || (self._currentTime = time, events.trigger(self, "timeupdate")) + + // Don't trigger events after user stop + if (!self._isFadingOut) { + self._currentTime = time; + events.trigger(self, 'timeupdate'); + } } function onVolumeChange() { - self._isFadingOut || (htmlMediaHelper.saveVolume(this.volume), events.trigger(self, "volumechange")) + + if (!self._isFadingOut) { + htmlMediaHelper.saveVolume(this.volume); + events.trigger(self, 'volumechange'); + } } function onPlaying(e) { - self._started || (self._started = !0, this.removeAttribute("controls"), htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks)), events.trigger(self, "playing") + + if (!self._started) { + self._started = true; + this.removeAttribute('controls'); + + htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks); + } + events.trigger(self, 'playing'); } function onPlay(e) { - events.trigger(self, "unpause") + + events.trigger(self, 'unpause'); } function onPause() { - events.trigger(self, "pause") + events.trigger(self, 'pause'); } function onError() { - var errorCode = this.error ? this.error.code || 0 : 0, - errorMessage = this.error ? this.error.message || "" : ""; - console.log("Media element error: " + errorCode.toString() + " " + errorMessage); + + var errorCode = this.error ? (this.error.code || 0) : 0; + var errorMessage = this.error ? (this.error.message || '') : ''; + console.log('Media element error: ' + errorCode.toString() + ' ' + errorMessage); + var type; + switch (errorCode) { case 1: + // MEDIA_ERR_ABORTED + // This will trigger when changing media while something is playing return; case 2: - type = "network"; + // MEDIA_ERR_NETWORK + type = 'network'; break; case 3: - if (self._hlsPlayer) return void htmlMediaHelper.handleHlsJsMediaError(self); - type = "mediadecodeerror"; + // MEDIA_ERR_DECODE + if (self._hlsPlayer) { + htmlMediaHelper.handleHlsJsMediaError(self); + return; + } else { + type = 'mediadecodeerror'; + } break; case 4: - type = "medianotsupported"; + // MEDIA_ERR_SRC_NOT_SUPPORTED + type = 'medianotsupported'; break; default: - return + // seeing cases where Edge is firing error events with no error code + // example is start playing something, then immediately change src to something else + return; } - htmlMediaHelper.onErrorInternal(self, type) - } - var self = this; - self.name = "Html Audio Player", self.type = "mediaplayer", self.id = "htmlaudioplayer", self.priority = 1, self.play = function(options) { - return self._started = !1, self._timeUpdated = !1, self._currentTime = null, setCurrentSrc(createMediaElement(), options) - }, self.stop = function(destroyPlayer) { - cancelFadeTimeout(); - var elem = self._mediaElement, - src = self._currentSrc; - if (elem && src) { - if (!destroyPlayer || !supportsFade()) return elem.pause(), htmlMediaHelper.onEndedInternal(self, elem, onError), destroyPlayer && self.destroy(), Promise.resolve(); - var originalVolume = elem.volume; - return fade(self, elem, elem.volume).then(function() { - elem.pause(), elem.volume = originalVolume, htmlMediaHelper.onEndedInternal(self, elem, onError), destroyPlayer && self.destroy() - }) - } - return Promise.resolve() - }, self.destroy = function() { - unBindEvents(self._mediaElement) + + htmlMediaHelper.onErrorInternal(self, type); } } - var fadeTimeout; - return HtmlAudioPlayer.prototype.currentSrc = function() { - return this._currentSrc - }, HtmlAudioPlayer.prototype.canPlayMediaType = function(mediaType) { - return "audio" === (mediaType || "").toLowerCase() - }, HtmlAudioPlayer.prototype.getDeviceProfile = function(item) { - return appHost.getDeviceProfile ? appHost.getDeviceProfile(item) : getDefaultProfile() - }, HtmlAudioPlayer.prototype.currentTime = function(val) { + + HtmlAudioPlayer.prototype.currentSrc = function () { + return this._currentSrc; + }; + + HtmlAudioPlayer.prototype.canPlayMediaType = function (mediaType) { + + return (mediaType || '').toLowerCase() === 'audio'; + }; + + HtmlAudioPlayer.prototype.getDeviceProfile = function (item) { + + if (appHost.getDeviceProfile) { + return appHost.getDeviceProfile(item); + } + + return getDefaultProfile(); + }; + + // Save this for when playback stops, because querying the time at that point might return 0 + HtmlAudioPlayer.prototype.currentTime = function (val) { + var mediaElement = this._mediaElement; if (mediaElement) { - if (null != val) return void(mediaElement.currentTime = val / 1e3); + if (val != null) { + mediaElement.currentTime = val / 1000; + return; + } + var currentTime = this._currentTime; - return currentTime ? 1e3 * currentTime : 1e3 * (mediaElement.currentTime || 0) + if (currentTime) { + return currentTime * 1000; + } + + return (mediaElement.currentTime || 0) * 1000; } - }, HtmlAudioPlayer.prototype.duration = function(val) { + }; + + HtmlAudioPlayer.prototype.duration = function (val) { + var mediaElement = this._mediaElement; if (mediaElement) { var duration = mediaElement.duration; - if (htmlMediaHelper.isValidDuration(duration)) return 1e3 * duration + if (htmlMediaHelper.isValidDuration(duration)) { + return duration * 1000; + } } - return null - }, HtmlAudioPlayer.prototype.seekable = function() { + + return null; + }; + + HtmlAudioPlayer.prototype.seekable = function () { var mediaElement = this._mediaElement; if (mediaElement) { + var seekable = mediaElement.seekable; if (seekable && seekable.length) { - var start = seekable.start(0), - end = seekable.end(0); - return htmlMediaHelper.isValidDuration(start) || (start = 0), htmlMediaHelper.isValidDuration(end) || (end = 0), end - start > 0 + + var start = seekable.start(0); + var end = seekable.end(0); + + if (!htmlMediaHelper.isValidDuration(start)) { + start = 0; + } + if (!htmlMediaHelper.isValidDuration(end)) { + end = 0; + } + + return (end - start) > 0; } - return !1 + + return false; } - }, HtmlAudioPlayer.prototype.getBufferedRanges = function() { + }; + + HtmlAudioPlayer.prototype.getBufferedRanges = function () { var mediaElement = this._mediaElement; - return mediaElement ? htmlMediaHelper.getBufferedRanges(this, mediaElement) : [] - }, HtmlAudioPlayer.prototype.pause = function() { + if (mediaElement) { + + return htmlMediaHelper.getBufferedRanges(this, mediaElement); + } + + return []; + }; + + HtmlAudioPlayer.prototype.pause = function () { var mediaElement = this._mediaElement; - mediaElement && mediaElement.pause() - }, HtmlAudioPlayer.prototype.resume = function() { + if (mediaElement) { + mediaElement.pause(); + } + }; + + // This is a retry after error + HtmlAudioPlayer.prototype.resume = function () { var mediaElement = this._mediaElement; - mediaElement && mediaElement.play() - }, HtmlAudioPlayer.prototype.unpause = function() { + if (mediaElement) { + mediaElement.play(); + } + }; + + HtmlAudioPlayer.prototype.unpause = function () { var mediaElement = this._mediaElement; - mediaElement && mediaElement.play() - }, HtmlAudioPlayer.prototype.paused = function() { + if (mediaElement) { + mediaElement.play(); + } + }; + + HtmlAudioPlayer.prototype.paused = function () { + var mediaElement = this._mediaElement; - return !!mediaElement && mediaElement.paused - }, HtmlAudioPlayer.prototype.setVolume = function(val) { + if (mediaElement) { + return mediaElement.paused; + } + + return false; + }; + + HtmlAudioPlayer.prototype.setVolume = function (val) { var mediaElement = this._mediaElement; - mediaElement && (mediaElement.volume = val / 100) - }, HtmlAudioPlayer.prototype.getVolume = function() { + if (mediaElement) { + mediaElement.volume = val / 100; + } + }; + + HtmlAudioPlayer.prototype.getVolume = function () { var mediaElement = this._mediaElement; - if (mediaElement) return Math.min(Math.round(100 * mediaElement.volume), 100) - }, HtmlAudioPlayer.prototype.volumeUp = function() { - this.setVolume(Math.min(this.getVolume() + 2, 100)) - }, HtmlAudioPlayer.prototype.volumeDown = function() { - this.setVolume(Math.max(this.getVolume() - 2, 0)) - }, HtmlAudioPlayer.prototype.setMute = function(mute) { + if (mediaElement) { + + return Math.min(Math.round(mediaElement.volume * 100), 100); + } + }; + + HtmlAudioPlayer.prototype.volumeUp = function () { + this.setVolume(Math.min(this.getVolume() + 2, 100)); + }; + + HtmlAudioPlayer.prototype.volumeDown = function () { + this.setVolume(Math.max(this.getVolume() - 2, 0)); + }; + + HtmlAudioPlayer.prototype.setMute = function (mute) { + var mediaElement = this._mediaElement; - mediaElement && (mediaElement.muted = mute) - }, HtmlAudioPlayer.prototype.isMuted = function() { + if (mediaElement) { + mediaElement.muted = mute; + } + }; + + HtmlAudioPlayer.prototype.isMuted = function () { var mediaElement = this._mediaElement; - return !!mediaElement && mediaElement.muted - }, HtmlAudioPlayer.prototype.destroy = function() {}, HtmlAudioPlayer + if (mediaElement) { + return mediaElement.muted; + } + return false; + }; + + HtmlAudioPlayer.prototype.destroy = function () { + + }; + + return HtmlAudioPlayer; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/htmlvideoplayer/htmlmediahelper.js b/src/bower_components/emby-webcomponents/htmlvideoplayer/htmlmediahelper.js index 68bc1ecded..bba0ec2daf 100644 --- a/src/bower_components/emby-webcomponents/htmlvideoplayer/htmlmediahelper.js +++ b/src/bower_components/emby-webcomponents/htmlvideoplayer/htmlmediahelper.js @@ -1,113 +1,254 @@ -define(["appSettings", "browser", "events"], function(appSettings, browser, events) { - "use strict"; +define(['appSettings', 'browser', 'events'], function (appSettings, browser, events) { + 'use strict'; function getSavedVolume() { - return appSettings.get("volume") || 1 + return appSettings.get("volume") || 1; } function saveVolume(value) { - value && appSettings.set("volume", value) + if (value) { + appSettings.set("volume", value); + } } function getCrossOriginValue(mediaSource) { - return mediaSource.IsRemote ? null : "anonymous" + + if (mediaSource.IsRemote) { + return null; + } + + return 'anonymous'; } function canPlayNativeHls() { - var media = document.createElement("video"); - return !(!media.canPlayType("application/x-mpegURL").replace(/no/, "") && !media.canPlayType("application/vnd.apple.mpegURL").replace(/no/, "")) + var media = document.createElement('video'); + + if (media.canPlayType('application/x-mpegURL').replace(/no/, '') || + media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) { + return true; + } + + return false; } function enableHlsShakaPlayer(item, mediaSource, mediaType) { - if (window.MediaSource && MediaSource.isTypeSupported) { + + if (!!window.MediaSource && !!MediaSource.isTypeSupported) { + if (canPlayNativeHls()) { - if (browser.edge && "Video" === mediaType) return !0; - mediaSource.RunTimeTicks + + if (browser.edge && mediaType === 'Video') { + return true; + } + + // simple playback should use the native support + if (mediaSource.RunTimeTicks) { + //if (!browser.edge) { + //return false; + //} + } + + //return false; } - return !0 + + return true; } - return !1 + + return false; } function enableHlsJsPlayer(runTimeTicks, mediaType) { - if (null == window.MediaSource) return !1; - if (browser.iOS) return !1; - if (browser.tizen || browser.web0s) return !1; - if (canPlayNativeHls()) { - if (browser.android && "Audio" === mediaType) return !0; - if (browser.edge, runTimeTicks) return !1 + + if (window.MediaSource == null) { + return false; } - return !0 + + // hls.js is only in beta. needs more testing. + if (browser.iOS) { + return false; + } + + // The native players on these devices support seeking live streams, no need to use hls.js here + if (browser.tizen || browser.web0s) { + return false; + } + + if (canPlayNativeHls()) { + + // Having trouble with chrome's native support and transcoded music + if (browser.android && mediaType === 'Audio') { + return true; + } + + if (browser.edge && mediaType === 'Video') { + //return true; + } + + // simple playback should use the native support + if (runTimeTicks) { + //if (!browser.edge) { + return false; + //} + } + + //return false; + } + + return true; } + var recoverDecodingErrorDate, recoverSwapAudioCodecDate; function handleHlsJsMediaError(instance, reject) { + var hlsPlayer = instance._hlsPlayer; - if (hlsPlayer) { - var now = Date.now(); - window.performance && window.performance.now && (now = performance.now()), !recoverDecodingErrorDate || now - recoverDecodingErrorDate > 3e3 ? (recoverDecodingErrorDate = now, console.log("try to recover media Error ..."), hlsPlayer.recoverMediaError()) : !recoverSwapAudioCodecDate || now - recoverSwapAudioCodecDate > 3e3 ? (recoverSwapAudioCodecDate = now, console.log("try to swap Audio Codec and recover media Error ..."), hlsPlayer.swapAudioCodec(), hlsPlayer.recoverMediaError()) : (console.error("cannot recover, last media error recovery failed ..."), reject ? reject() : onErrorInternal(instance, "mediadecodeerror")) + + if (!hlsPlayer) { + return; + } + + var now = Date.now(); + + if (window.performance && window.performance.now) { + now = performance.now(); + } + + if (!recoverDecodingErrorDate || (now - recoverDecodingErrorDate) > 3000) { + recoverDecodingErrorDate = now; + console.log('try to recover media Error ...'); + hlsPlayer.recoverMediaError(); + } else { + if (!recoverSwapAudioCodecDate || (now - recoverSwapAudioCodecDate) > 3000) { + recoverSwapAudioCodecDate = now; + console.log('try to swap Audio Codec and recover media Error ...'); + hlsPlayer.swapAudioCodec(); + hlsPlayer.recoverMediaError(); + } else { + console.error('cannot recover, last media error recovery failed ...'); + + if (reject) { + reject(); + } else { + onErrorInternal(instance, 'mediadecodeerror'); + } + } } } function onErrorInternal(instance, type) { - instance.destroyCustomTrack && instance.destroyCustomTrack(instance._mediaElement), events.trigger(instance, "error", [{ - type: type - }]) + + // Needed for video + if (instance.destroyCustomTrack) { + instance.destroyCustomTrack(instance._mediaElement); + } + + events.trigger(instance, 'error', [ + { + type: type + }]); } function isValidDuration(duration) { - return !(!duration || isNaN(duration) || duration === Number.POSITIVE_INFINITY || duration === Number.NEGATIVE_INFINITY) + if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) { + return true; + } + + return false; } - function setCurrentTimeIfNeeded(element, seconds, allowance) { - Math.abs((element.currentTime || 0) - seconds) >= allowance && (element.currentTime = seconds) + function setCurrentTimeIfNeeded(element, seconds) { + + if (Math.abs(element.currentTime || 0, seconds) <= 1) { + element.currentTime = seconds; + } } function seekOnPlaybackStart(instance, element, ticks) { - var seconds = (ticks || 0) / 1e7; + + var seconds = (ticks || 0) / 10000000; + if (seconds) { - (instance.currentSrc() || "").toLowerCase(); - setCurrentTimeIfNeeded(element, seconds, 5), setTimeout(function() { - setCurrentTimeIfNeeded(element, seconds, 10) - }, 2500) + var src = (instance.currentSrc() || '').toLowerCase(); + + // Appending #t=xxx to the query string doesn't seem to work with HLS + // For plain video files, not all browsers support it either + var delay = browser.safari ? 2500 : 0; + if (delay) { + setTimeout(function () { + setCurrentTimeIfNeeded(element, seconds); + }, delay); + } else { + setCurrentTimeIfNeeded(element, seconds); + } } } function applySrc(elem, src, options) { - return window.Windows && options.mediaSource && options.mediaSource.IsLocal ? Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function(file) { - var playlist = new Windows.Media.Playback.MediaPlaybackList, - source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file), - startTime = (options.playerStartPositionTicks || 0) / 1e4; - return playlist.items.append(new Windows.Media.Playback.MediaPlaybackItem(source1, startTime)), elem.src = URL.createObjectURL(playlist, { - oneTimeOnly: !0 - }), Promise.resolve() - }) : (elem.src = src, Promise.resolve()) + + if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) { + + return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) { + + var playlist = new Windows.Media.Playback.MediaPlaybackList(); + + var source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file); + var startTime = (options.playerStartPositionTicks || 0) / 10000; + playlist.items.append(new Windows.Media.Playback.MediaPlaybackItem(source1, startTime)); + elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true }); + return Promise.resolve(); + }); + + } else { + + elem.src = src; + } + + return Promise.resolve(); } function onSuccessfulPlay(elem, onErrorFn) { - elem.addEventListener("error", onErrorFn) + + elem.addEventListener('error', onErrorFn); } function playWithPromise(elem, onErrorFn) { + try { var promise = elem.play(); - return promise && promise.then ? promise.catch(function(e) { - var errorName = (e.name || "").toLowerCase(); - return "notallowederror" === errorName || "aborterror" === errorName ? (onSuccessfulPlay(elem, onErrorFn), Promise.resolve()) : Promise.reject() - }) : (onSuccessfulPlay(elem, onErrorFn), Promise.resolve()) + if (promise && promise.then) { + // Chrome now returns a promise + return promise.catch(function (e) { + + var errorName = (e.name || '').toLowerCase(); + // safari uses aborterror + if (errorName === 'notallowederror' || + errorName === 'aborterror') { + // swallow this error because the user can still click the play button on the video element + onSuccessfulPlay(elem, onErrorFn); + return Promise.resolve(); + } + return Promise.reject(); + }); + } else { + onSuccessfulPlay(elem, onErrorFn); + return Promise.resolve(); + } } catch (err) { - return console.log("error calling video.play: " + err), Promise.reject() + console.log('error calling video.play: ' + err); + return Promise.reject(); } } function destroyCastPlayer(instance) { + var player = instance._castPlayer; if (player) { try { - player.unload() + player.unload(); } catch (err) { - console.log(err) + console.log(err); } - instance._castPlayer = null + + instance._castPlayer = null; } } @@ -115,11 +256,12 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even var player = instance._shakaPlayer; if (player) { try { - player.destroy() + player.destroy(); } catch (err) { - console.log(err) + console.log(err); } - instance._shakaPlayer = null + + instance._shakaPlayer = null; } } @@ -127,11 +269,12 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even var player = instance._hlsPlayer; if (player) { try { - player.destroy() + player.destroy(); } catch (err) { - console.log(err) + console.log(err); } - instance._hlsPlayer = null + + instance._hlsPlayer = null; } } @@ -139,63 +282,170 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even var player = instance._flvPlayer; if (player) { try { - player.unload(), player.detachMediaElement(), player.destroy() + player.unload(); + player.detachMediaElement(); + player.destroy(); } catch (err) { - console.log(err) + console.log(err); } - instance._flvPlayer = null + + instance._flvPlayer = null; } } function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) { - hls.on(Hls.Events.MANIFEST_PARSED, function() { - playWithPromise(elem, onErrorFn).then(resolve, function() { - reject && (reject(), reject = null) - }) - }), hls.on(Hls.Events.ERROR, function(event, data) { - switch (console.log("HLS Error: Type: " + data.type + " Details: " + (data.details || "") + " Fatal: " + (data.fatal || !1)), data.type) { + + hls.on(Hls.Events.MANIFEST_PARSED, function () { + playWithPromise(elem, onErrorFn).then(resolve, function () { + + if (reject) { + reject(); + reject = null; + } + }); + }); + + hls.on(Hls.Events.ERROR, function (event, data) { + + console.log('HLS Error: Type: ' + data.type + ' Details: ' + (data.details || '') + ' Fatal: ' + (data.fatal || false)); + + switch (data.type) { case Hls.ErrorTypes.NETWORK_ERROR: - if (data.response && data.response.code && data.response.code >= 400) return console.log("hls.js response error code: " + data.response.code), hls.destroy(), void(reject ? (reject("servererror"), reject = null) : onErrorInternal(instance, "servererror")) - } - if (data.fatal) switch (data.type) { - case Hls.ErrorTypes.NETWORK_ERROR: - data.response && 0 === data.response.code ? (console.log("hls.js response error code: " + data.response.code), hls.destroy(), reject ? (reject("network"), reject = null) : onErrorInternal(instance, "network")) : (console.log("fatal network error encountered, try to recover"), hls.startLoad()); - break; - case Hls.ErrorTypes.MEDIA_ERROR: - console.log("fatal media error encountered, try to recover"); - var currentReject = reject; - reject = null, handleHlsJsMediaError(instance, currentReject); + // try to recover network error + if (data.response && data.response.code && data.response.code >= 400) { + + console.log('hls.js response error code: ' + data.response.code); + + // Trigger failure differently depending on whether this is prior to start of playback, or after + hls.destroy(); + + if (reject) { + reject('servererror'); + reject = null; + } else { + onErrorInternal(instance, 'servererror'); + } + + return; + + } + break; default: - console.log("Cannot recover from hls error - destroy and trigger error"), hls.destroy(), reject ? (reject(), reject = null) : onErrorInternal(instance, "mediadecodeerror") + break; } - }) + + if (data.fatal) { + switch (data.type) { + case Hls.ErrorTypes.NETWORK_ERROR: + + if (data.response && data.response.code === 0) { + + // This could be a CORS error related to access control response headers + + console.log('hls.js response error code: ' + data.response.code); + + // Trigger failure differently depending on whether this is prior to start of playback, or after + hls.destroy(); + + if (reject) { + reject('network'); + reject = null; + } else { + onErrorInternal(instance, 'network'); + } + } + + else { + console.log("fatal network error encountered, try to recover"); + hls.startLoad(); + } + + break; + case Hls.ErrorTypes.MEDIA_ERROR: + console.log("fatal media error encountered, try to recover"); + var currentReject = reject; + reject = null; + handleHlsJsMediaError(instance, currentReject); + break; + default: + + console.log('Cannot recover from hls error - destroy and trigger error'); + // cannot recover + // Trigger failure differently depending on whether this is prior to start of playback, or after + hls.destroy(); + + if (reject) { + reject(); + reject = null; + } else { + onErrorInternal(instance, 'mediadecodeerror'); + } + break; + } + } + }); } function onEndedInternal(instance, elem, onErrorFn) { - elem.removeEventListener("error", onErrorFn), elem.src = "", elem.innerHTML = "", elem.removeAttribute("src"), destroyHlsPlayer(instance), destroyFlvPlayer(instance), destroyShakaPlayer(instance), destroyCastPlayer(instance); + + elem.removeEventListener('error', onErrorFn); + + elem.src = ''; + elem.innerHTML = ''; + elem.removeAttribute("src"); + + destroyHlsPlayer(instance); + destroyFlvPlayer(instance); + destroyShakaPlayer(instance); + destroyCastPlayer(instance); + var stopInfo = { src: instance._currentSrc }; - events.trigger(instance, "stopped", [stopInfo]), instance._currentTime = null, instance._currentSrc = null, instance._currentPlayOptions = null + + events.trigger(instance, 'stopped', [stopInfo]); + + instance._currentTime = null; + instance._currentSrc = null; + instance._currentPlayOptions = null; } function getBufferedRanges(instance, elem) { - var offset, ranges = [], - seekable = elem.buffered || [], - currentPlayOptions = instance._currentPlayOptions; - currentPlayOptions && (offset = currentPlayOptions.transcodingOffsetTicks), offset = offset || 0; - for (var i = 0, length = seekable.length; i < length; i++) { - var start = seekable.start(i), - end = seekable.end(i); - isValidDuration(start) || (start = 0), isValidDuration(end) ? ranges.push({ - start: 1e7 * start + offset, - end: 1e7 * end + offset - }) : end = 0 + + var ranges = []; + var seekable = elem.buffered || []; + + var offset; + var currentPlayOptions = instance._currentPlayOptions; + if (currentPlayOptions) { + offset = currentPlayOptions.transcodingOffsetTicks; } - return ranges + + offset = offset || 0; + + for (var i = 0, length = seekable.length; i < length; i++) { + + var start = seekable.start(i); + var end = seekable.end(i); + + if (!isValidDuration(start)) { + start = 0; + } + if (!isValidDuration(end)) { + end = 0; + continue; + } + + ranges.push({ + start: (start * 10000000) + offset, + end: (end * 10000000) + offset + }); + } + + return ranges; } - var recoverDecodingErrorDate, recoverSwapAudioCodecDate; + return { getSavedVolume: getSavedVolume, saveVolume: saveVolume, @@ -214,5 +464,5 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even onEndedInternal: onEndedInternal, getCrossOriginValue: getCrossOriginValue, getBufferedRanges: getBufferedRanges - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/htmlvideoplayer/plugin.js b/src/bower_components/emby-webcomponents/htmlvideoplayer/plugin.js index 35313d6782..16381d4462 100644 --- a/src/bower_components/emby-webcomponents/htmlvideoplayer/plugin.js +++ b/src/bower_components/emby-webcomponents/htmlvideoplayer/plugin.js @@ -1,699 +1,1852 @@ -define(["browser", "require", "events", "apphost", "loading", "dom", "playbackManager", "appRouter", "appSettings", "connectionManager", "htmlMediaHelper", "itemHelper"], function(browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper) { +define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager', 'htmlMediaHelper', 'itemHelper'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper) { "use strict"; + var mediaManager; + function tryRemoveElement(elem) { var parentNode = elem.parentNode; - if (parentNode) try { - parentNode.removeChild(elem) - } catch (err) { - console.log("Error removing dialog element: " + err) + if (parentNode) { + + // Seeing crashes in edge webview + try { + parentNode.removeChild(elem); + } catch (err) { + console.log('Error removing dialog element: ' + err); + } } } + var _supportsTextTracks; + function supportsTextTracks() { + + if (_supportsTextTracks == null) { + _supportsTextTracks = document.createElement('video').textTracks != null; + } + + // For now, until ready + return _supportsTextTracks; + } + function enableNativeTrackSupport(currentSrc, track) { - if (track && "Embed" === track.DeliveryMethod) return !0; - if (browser.firefox && -1 !== (currentSrc || "").toLowerCase().indexOf(".m3u8")) return !1; - if (browser.chromecast && -1 !== (currentSrc || "").toLowerCase().indexOf(".m3u8")) return !1; - if (browser.ps4) return !1; - if (browser.web0s) return !1; - if (browser.edge) return !1; - if (browser.iOS && (browser.iosVersion || 10) < 10) return !1; + if (track) { - var format = (track.Codec || "").toLowerCase(); - if ("ssa" === format || "ass" === format) return !1 + if (track.DeliveryMethod === 'Embed') { + return true; + } } - return !0 + + if (browser.firefox) { + if ((currentSrc || '').toLowerCase().indexOf('.m3u8') !== -1) { + return false; + } + } + + // subs getting blocked due to CORS + if (browser.chromecast) { + if ((currentSrc || '').toLowerCase().indexOf('.m3u8') !== -1) { + return false; + } + } + + if (browser.ps4) { + return false; + } + + if (browser.web0s) { + return false; + } + + // Edge is randomly not rendering subtitles + if (browser.edge) { + return false; + } + + if (browser.iOS) { + // works in the browser but not the native app + if ((browser.iosVersion || 10) < 10) { + return false; + } + } + + if (track) { + var format = (track.Codec || '').toLowerCase(); + if (format === 'ssa' || format === 'ass') { + // libjass is needed here + return false; + } + } + + return true; } function requireHlsPlayer(callback) { - require(["hlsjs"], function(hls) { - window.Hls = hls, callback() - }) + require(['hlsjs'], function (hls) { + window.Hls = hls; + callback(); + }); } function getMediaStreamAudioTracks(mediaSource) { - return mediaSource.MediaStreams.filter(function(s) { - return "Audio" === s.Type - }) + + return mediaSource.MediaStreams.filter(function (s) { + return s.Type === 'Audio'; + }); } function getMediaStreamTextTracks(mediaSource) { - return mediaSource.MediaStreams.filter(function(s) { - return "Subtitle" === s.Type - }) + + return mediaSource.MediaStreams.filter(function (s) { + return s.Type === 'Subtitle'; + }); } function zoomIn(elem) { - return new Promise(function(resolve, reject) { - elem.style.animation = "htmlvideoplayer-zoomin 240ms ease-in normal", dom.addEventListener(elem, dom.whichAnimationEvent(), resolve, { - once: !0 - }) - }) + + return new Promise(function (resolve, reject) { + + var duration = 240; + elem.style.animation = 'htmlvideoplayer-zoomin ' + duration + 'ms ease-in normal'; + dom.addEventListener(elem, dom.whichAnimationEvent(), resolve, { + once: true + }); + }); } function normalizeTrackEventText(text) { - return text.replace(/\\N/gi, "\n") + return text.replace(/\\N/gi, '\n'); } function setTracks(elem, tracks, item, mediaSource) { - elem.innerHTML = getTracksHtml(tracks, item, mediaSource) + + elem.innerHTML = getTracksHtml(tracks, item, mediaSource); } function getTextTrackUrl(track, item, format) { - if (itemHelper.isLocalItem(item) && track.Path) return track.Path; + + if (itemHelper.isLocalItem(item) && track.Path) { + return track.Path; + } + var url = playbackManager.getSubtitleUrl(track, item.ServerId); - return format && (url = url.replace(".vtt", format)), url + if (format) { + url = url.replace('.vtt', format); + } + + return url; } function getTracksHtml(tracks, item, mediaSource) { - return tracks.map(function(t) { - if ("External" !== t.DeliveryMethod) return ""; - var defaultAttribute = mediaSource.DefaultSubtitleStreamIndex === t.Index ? " default" : "", - language = t.Language || "und", - label = t.Language || "und"; - return '" - }).join("") + return tracks.map(function (t) { + + if (t.DeliveryMethod !== 'External') { + return ''; + } + + var defaultAttribute = mediaSource.DefaultSubtitleStreamIndex === t.Index ? ' default' : ''; + + var language = t.Language || 'und'; + var label = t.Language || 'und'; + return ''; + + }).join(''); } function getDefaultProfile() { - return new Promise(function(resolve, reject) { - require(["browserdeviceprofile"], function(profileBuilder) { - resolve(profileBuilder({})) - }) - }) + + return new Promise(function (resolve, reject) { + + require(['browserdeviceprofile'], function (profileBuilder) { + + resolve(profileBuilder({})); + }); + }); } function HtmlVideoPlayer() { - function updateVideoUrl(streamInfo) { - var isHls = -1 !== streamInfo.url.toLowerCase().indexOf(".m3u8"), - mediaSource = streamInfo.mediaSource, - item = streamInfo.item; - if (mediaSource && item && !mediaSource.RunTimeTicks && isHls && "Transcode" === streamInfo.playMethod && (browser.iOS || browser.osx)) { - var hlsPlaylistUrl = streamInfo.url.replace("master.m3u8", "live.m3u8"); - return loading.show(), console.log("prefetching hls playlist: " + hlsPlaylistUrl), connectionManager.getApiClient(item.ServerId).ajax({ - type: "GET", - url: hlsPlaylistUrl - }).then(function() { - return console.log("completed prefetching hls playlist: " + hlsPlaylistUrl), loading.hide(), streamInfo.url = hlsPlaylistUrl, Promise.resolve() - }, function() { - return console.log("error prefetching hls playlist: " + hlsPlaylistUrl), loading.hide(), Promise.resolve() - }) - } - return Promise.resolve() + + if (browser.edgeUwp) { + this.name = 'Windows Video Player'; + } else { + this.name = 'Html Video Player'; } + this.type = 'mediaplayer'; + this.id = 'htmlvideoplayer'; + + // Let any players created by plugins take priority + this.priority = 1; + + var videoDialog; + + var winJsPlaybackItem; + + var subtitleTrackIndexToSetOnPlaying; + var audioTrackIndexToSetOnPlaying; + + var lastCustomTrackMs = 0; + var currentClock; + var currentAssRenderer; + var customTrackIndex = -1; + + var videoSubtitlesElem; + var currentTrackEvents; + + var self = this; + + self.currentSrc = function () { + return self._currentSrc; + }; + + function updateVideoUrl(streamInfo) { + + var isHls = streamInfo.url.toLowerCase().indexOf('.m3u8') !== -1; + + var mediaSource = streamInfo.mediaSource; + var item = streamInfo.item; + + // Huge hack alert. Safari doesn't seem to like if the segments aren't available right away when playback starts + // This will start the transcoding process before actually feeding the video url into the player + // Edit: Also seeing stalls from hls.js + if (mediaSource && item && !mediaSource.RunTimeTicks && isHls && streamInfo.playMethod === 'Transcode' && (browser.iOS || browser.osx)) { + + var hlsPlaylistUrl = streamInfo.url.replace('master.m3u8', 'live.m3u8'); + + loading.show(); + + console.log('prefetching hls playlist: ' + hlsPlaylistUrl); + + return connectionManager.getApiClient(item.ServerId).ajax({ + + type: 'GET', + url: hlsPlaylistUrl + + }).then(function () { + + console.log('completed prefetching hls playlist: ' + hlsPlaylistUrl); + + loading.hide(); + streamInfo.url = hlsPlaylistUrl; + + return Promise.resolve(); + + }, function () { + + console.log('error prefetching hls playlist: ' + hlsPlaylistUrl); + + loading.hide(); + return Promise.resolve(); + }); + + } else { + return Promise.resolve(); + } + } + + self.play = function (options) { + + if (browser.msie) { + if (options.playMethod === 'Transcode' && !window.MediaSource) { + alert('Playback of this content is not supported in Internet Explorer. For a better experience, try a modern browser such as Microsoft Edge, Google Chrome, Firefox or Opera.'); + return Promise.reject(); + } + } + + self._started = false; + self._timeUpdated = false; + + self._currentTime = null; + + return createMediaElement(options).then(function (elem) { + + return updateVideoUrl(options, options.mediaSource).then(function () { + return setCurrentSrc(elem, options); + }); + }); + }; + function setSrcWithFlvJs(instance, elem, options, url) { - return new Promise(function(resolve, reject) { - require(["flvjs"], function(flvjs) { + + return new Promise(function (resolve, reject) { + + require(['flvjs'], function (flvjs) { + var flvPlayer = flvjs.createPlayer({ - type: "flv", + type: 'flv', url: url - }, { - seekType: "range", - lazyLoad: !1 - }); - flvPlayer.attachMediaElement(elem), flvPlayer.load(), flvPlayer.play().then(resolve, reject), instance._flvPlayer = flvPlayer, self._currentSrc = url - }) - }) + }, + { + seekType: 'range', + lazyLoad: false + }); + + flvPlayer.attachMediaElement(elem); + flvPlayer.load(); + + flvPlayer.play().then(resolve, reject); + instance._flvPlayer = flvPlayer; + + // This is needed in setCurrentTrackElement + self._currentSrc = url; + }); + }); } function setSrcWithHlsJs(instance, elem, options, url) { - return new Promise(function(resolve, reject) { - requireHlsPlayer(function() { + + return new Promise(function (resolve, reject) { + + requireHlsPlayer(function () { + var hls = new Hls({ - manifestLoadingTimeOut: 2e4 + manifestLoadingTimeOut: 20000 + //appendErrorMaxRetry: 6, + //debug: true }); - hls.loadSource(url), hls.attachMedia(elem), htmlMediaHelper.bindEventsToHlsPlayer(self, hls, elem, onError, resolve, reject), self._hlsPlayer = hls, self._currentSrc = url - }) - }) + hls.loadSource(url); + hls.attachMedia(elem); + + htmlMediaHelper.bindEventsToHlsPlayer(self, hls, elem, onError, resolve, reject); + + self._hlsPlayer = hls; + + // This is needed in setCurrentTrackElement + self._currentSrc = url; + }); + }); + } + + function onShakaError(event) { + + var error = event.detail; + console.error('Error code', error.code, 'object', error); + } + + function setSrcWithShakaPlayer(instance, elem, options, url) { + + return new Promise(function (resolve, reject) { + + require(['shaka'], function () { + + var player = new shaka.Player(elem); + + //player.configure({ + // abr: { + // enabled: false + // }, + // streaming: { + + // failureCallback: function () { + // alert(2); + // } + // } + //}); + + //shaka.log.setLevel(6); + + // Listen for error events. + player.addEventListener('error', onShakaError); + + // Try to load a manifest. + // This is an asynchronous process. + player.load(url).then(function () { + + // This runs if the asynchronous load is successful. + resolve(); + + }, reject); + + self._shakaPlayer = player; + + // This is needed in setCurrentTrackElement + self._currentSrc = url; + }); + }); } function setCurrentSrcChromecast(instance, elem, options, url) { - elem.autoplay = !0; - var lrd = new cast.receiver.MediaManager.LoadRequestData; - lrd.currentTime = (options.playerStartPositionTicks || 0) / 1e7, lrd.autoplay = !0, lrd.media = new cast.receiver.media.MediaInformation, lrd.media.contentId = url, lrd.media.contentType = options.mimeType, lrd.media.streamType = cast.receiver.media.StreamType.OTHER, lrd.media.customData = options, console.log("loading media url into mediaManager"); + + elem.autoplay = true; + + var lrd = new cast.receiver.MediaManager.LoadRequestData(); + lrd.currentTime = (options.playerStartPositionTicks || 0) / 10000000; + lrd.autoplay = true; + lrd.media = new cast.receiver.media.MediaInformation(); + + lrd.media.contentId = url; + lrd.media.contentType = options.mimeType; + lrd.media.streamType = cast.receiver.media.StreamType.OTHER; + lrd.media.customData = options; + + console.log('loading media url into mediaManager'); + try { - return mediaManager.load(lrd), self._currentSrc = url, Promise.resolve() + mediaManager.load(lrd); + // This is needed in setCurrentTrackElement + self._currentSrc = url; + + return Promise.resolve(); } catch (err) { - return console.log("mediaManager error: " + err), Promise.reject() + + console.log('mediaManager error: ' + err); + return Promise.reject(); } } + // Adapted from : https://github.com/googlecast/CastReferencePlayer/blob/master/player.js function onMediaManagerLoadMedia(event) { - self._castPlayer && self._castPlayer.unload(), self._castPlayer = null; - var protocol, data = event.data, - media = event.data.media || {}, - url = media.contentId, - contentType = media.contentType.toLowerCase(), - mediaElement = (media.customData, self._mediaElement), - host = new cast.player.api.Host({ - url: url, - mediaElement: mediaElement - }); - protocol = cast.player.api.CreateHlsStreamingProtocol(host), console.log("loading playback url: " + url), console.log("contentType: " + contentType), host.onError = function(errorCode) { - console.log("Fatal Error - " + errorCode) - }, mediaElement.autoplay = !1, self._castPlayer = new cast.player.api.Player(host), self._castPlayer.load(protocol, data.currentTime || 0), self._castPlayer.playWhenHaveEnoughData() + + if (self._castPlayer) { + self._castPlayer.unload(); // Must unload before starting again. + } + self._castPlayer = null; + + var data = event.data; + + var media = event.data.media || {}; + var url = media.contentId; + var contentType = media.contentType.toLowerCase(); + var options = media.customData; + + var protocol; + var ext = 'm3u8'; + + var mediaElement = self._mediaElement; + + var host = new cast.player.api.Host({ + 'url': url, + 'mediaElement': mediaElement + }); + + if (ext === 'm3u8' || + contentType === 'application/x-mpegurl' || + contentType === 'application/vnd.apple.mpegurl') { + protocol = cast.player.api.CreateHlsStreamingProtocol(host); + } else if (ext === 'mpd' || + contentType === 'application/dash+xml') { + protocol = cast.player.api.CreateDashStreamingProtocol(host); + } else if (url.indexOf('.ism') > -1 || + contentType === 'application/vnd.ms-sstr+xml') { + protocol = cast.player.api.CreateSmoothStreamingProtocol(host); + } + + console.log('loading playback url: ' + url); + console.log('contentType: ' + contentType); + + host.onError = function (errorCode) { + console.log("Fatal Error - " + errorCode); + }; + + mediaElement.autoplay = false; + + self._castPlayer = new cast.player.api.Player(host); + + self._castPlayer.load(protocol, data.currentTime || 0); + + self._castPlayer.playWhenHaveEnoughData(); } function initMediaManager() { - mediaManager.defaultOnLoad = mediaManager.onLoad.bind(mediaManager), mediaManager.onLoad = onMediaManagerLoadMedia.bind(self), mediaManager.defaultOnStop = mediaManager.onStop.bind(mediaManager), mediaManager.onStop = function(event) { - playbackManager.stop(), mediaManager.defaultOnStop(event) - } + + mediaManager.defaultOnLoad = mediaManager.onLoad.bind(mediaManager); + mediaManager.onLoad = onMediaManagerLoadMedia.bind(self); + + //mediaManager.defaultOnPlay = mediaManager.onPlay.bind(mediaManager); + //mediaManager.onPlay = function (event) { + // // TODO ??? + // mediaManager.defaultOnPlay(event); + //}; + + mediaManager.defaultOnStop = mediaManager.onStop.bind(mediaManager); + mediaManager.onStop = function (event) { + playbackManager.stop(); + mediaManager.defaultOnStop(event); + }; } function setCurrentSrc(elem, options) { - elem.removeEventListener("error", onError); + + elem.removeEventListener('error', onError); + var val = options.url; - console.log("playing url: " + val); - var seconds = (options.playerStartPositionTicks || 0) / 1e7; - seconds && (val += "#t=" + seconds), htmlMediaHelper.destroyHlsPlayer(self), htmlMediaHelper.destroyFlvPlayer(self), htmlMediaHelper.destroyCastPlayer(self); - var tracks = getMediaStreamTextTracks(options.mediaSource); - if (null != (subtitleTrackIndexToSetOnPlaying = null == options.mediaSource.DefaultSubtitleStreamIndex ? -1 : options.mediaSource.DefaultSubtitleStreamIndex) && subtitleTrackIndexToSetOnPlaying >= 0) { - var initialSubtitleStream = options.mediaSource.MediaStreams[subtitleTrackIndexToSetOnPlaying]; - initialSubtitleStream && "Encode" !== initialSubtitleStream.DeliveryMethod || (subtitleTrackIndexToSetOnPlaying = -1) + console.log('playing url: ' + val); + + // Convert to seconds + var seconds = (options.playerStartPositionTicks || 0) / 10000000; + if (seconds) { + val += '#t=' + seconds; } - audioTrackIndexToSetOnPlaying = "Transcode" === options.playMethod ? null : options.mediaSource.DefaultAudioStreamIndex, self._currentPlayOptions = options; + + htmlMediaHelper.destroyHlsPlayer(self); + htmlMediaHelper.destroyFlvPlayer(self); + htmlMediaHelper.destroyCastPlayer(self); + + var tracks = getMediaStreamTextTracks(options.mediaSource); + + subtitleTrackIndexToSetOnPlaying = options.mediaSource.DefaultSubtitleStreamIndex == null ? -1 : options.mediaSource.DefaultSubtitleStreamIndex; + if (subtitleTrackIndexToSetOnPlaying != null && subtitleTrackIndexToSetOnPlaying >= 0) { + var initialSubtitleStream = options.mediaSource.MediaStreams[subtitleTrackIndexToSetOnPlaying]; + if (!initialSubtitleStream || initialSubtitleStream.DeliveryMethod === 'Encode') { + subtitleTrackIndexToSetOnPlaying = -1; + } + } + + audioTrackIndexToSetOnPlaying = options.playMethod === 'Transcode' ? null : options.mediaSource.DefaultAudioStreamIndex; + + self._currentPlayOptions = options; + var crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource); - return crossOrigin && (elem.crossOrigin = crossOrigin), browser.chromecast && -1 !== val.indexOf(".m3u8") && options.mediaSource.RunTimeTicks ? (setTracks(elem, tracks, options.item, options.mediaSource), setCurrentSrcChromecast(self, elem, options, val)) : htmlMediaHelper.enableHlsJsPlayer(options.mediaSource.RunTimeTicks, "Video") && -1 !== val.indexOf(".m3u8") ? (setTracks(elem, tracks, options.item, options.mediaSource), setSrcWithHlsJs(self, elem, options, val)) : "Transcode" !== options.playMethod && "flv" === options.mediaSource.Container ? (setTracks(elem, tracks, options.item, options.mediaSource), setSrcWithFlvJs(self, elem, options, val)) : (elem.autoplay = !0, htmlMediaHelper.applySrc(elem, val, options).then(function() { - return setTracks(elem, tracks, options.item, options.mediaSource), self._currentSrc = val, htmlMediaHelper.playWithPromise(elem, onError) - })) + if (crossOrigin) { + elem.crossOrigin = crossOrigin; + } + + /*if (htmlMediaHelper.enableHlsShakaPlayer(options.item, options.mediaSource, 'Video') && val.indexOf('.m3u8') !== -1) { + + setTracks(elem, tracks, options.item, options.mediaSource); + + return setSrcWithShakaPlayer(self, elem, options, val); + + } else*/ if (browser.chromecast && val.indexOf('.m3u8') !== -1 && options.mediaSource.RunTimeTicks) { + + setTracks(elem, tracks, options.item, options.mediaSource); + return setCurrentSrcChromecast(self, elem, options, val); + } + + else if (htmlMediaHelper.enableHlsJsPlayer(options.mediaSource.RunTimeTicks, 'Video') && val.indexOf('.m3u8') !== -1) { + + setTracks(elem, tracks, options.item, options.mediaSource); + + return setSrcWithHlsJs(self, elem, options, val); + + } else if (options.playMethod !== 'Transcode' && options.mediaSource.Container === 'flv') { + + setTracks(elem, tracks, options.item, options.mediaSource); + + return setSrcWithFlvJs(self, elem, options, val); + + } else { + + elem.autoplay = true; + + return htmlMediaHelper.applySrc(elem, val, options).then(function () { + + setTracks(elem, tracks, options.item, options.mediaSource); + + self._currentSrc = val; + + return htmlMediaHelper.playWithPromise(elem, onError); + }); + } } + self.setSubtitleStreamIndex = function (index) { + + setCurrentTrackElement(index); + }; + function isAudioStreamSupported(stream, deviceProfile) { - var codec = (stream.Codec || "").toLowerCase(); - return !codec || (!deviceProfile || (deviceProfile.DirectPlayProfiles || []).filter(function(p) { - return "Video" === p.Type && (!p.AudioCodec || -1 !== p.AudioCodec.toLowerCase().indexOf(codec)) - }).length > 0) + + var codec = (stream.Codec || '').toLowerCase(); + + if (!codec) { + return true; + } + + if (!deviceProfile) { + // This should never happen + return true; + } + + var profiles = deviceProfile.DirectPlayProfiles || []; + + return profiles.filter(function (p) { + + + if (p.Type === 'Video') { + + if (!p.AudioCodec) { + return true; + } + + return p.AudioCodec.toLowerCase().indexOf(codec) !== -1; + } + + return false; + + }).length > 0; } function getSupportedAudioStreams() { var profile = self._lastProfile; - return getMediaStreamAudioTracks(self._currentPlayOptions.mediaSource).filter(function(stream) { - return isAudioStreamSupported(stream, profile) - }) + + return getMediaStreamAudioTracks(self._currentPlayOptions.mediaSource).filter(function (stream) { + return isAudioStreamSupported(stream, profile); + }); } + self.setAudioStreamIndex = function (index) { + + var streams = getSupportedAudioStreams(); + + if (streams.length < 2) { + // If there's only one supported stream then trust that the player will handle it on it's own + return; + } + + var audioIndex = -1; + var i, length, stream; + + for (i = 0, length = streams.length; i < length; i++) { + stream = streams[i]; + + audioIndex++; + + if (stream.Index === index) { + break; + } + } + + if (audioIndex === -1) { + return; + } + + var elem = self._mediaElement; + if (!elem) { + return; + } + + // https://msdn.microsoft.com/en-us/library/hh772507(v=vs.85).aspx + + var elemAudioTracks = elem.audioTracks || []; + console.log('found ' + elemAudioTracks.length + ' audio tracks'); + + for (i = 0, length = elemAudioTracks.length; i < length; i++) { + + if (audioIndex === i) { + console.log('setting audio track ' + i + ' to enabled'); + elemAudioTracks[i].enabled = true; + } else { + console.log('setting audio track ' + i + ' to disabled'); + elemAudioTracks[i].enabled = false; + } + } + + setTimeout(function () { + elem.currentTime = elem.currentTime; + }, 100); + }; + + self.stop = function (destroyPlayer) { + + var elem = self._mediaElement; + var src = self._currentSrc; + + if (elem) { + + if (src) { + elem.pause(); + } + + htmlMediaHelper.onEndedInternal(self, elem, onError); + + if (destroyPlayer) { + self.destroy(); + } + } + + destroyCustomTrack(elem); + + return Promise.resolve(); + }; + + self.destroy = function () { + + htmlMediaHelper.destroyHlsPlayer(self); + htmlMediaHelper.destroyFlvPlayer(self); + + appRouter.setTransparency('none'); + + var videoElement = self._mediaElement; + + if (videoElement) { + + self._mediaElement = null; + + destroyCustomTrack(videoElement); + + videoElement.removeEventListener('timeupdate', onTimeUpdate); + videoElement.removeEventListener('ended', onEnded); + videoElement.removeEventListener('volumechange', onVolumeChange); + videoElement.removeEventListener('pause', onPause); + videoElement.removeEventListener('playing', onPlaying); + videoElement.removeEventListener('play', onPlay); + videoElement.removeEventListener('click', onClick); + videoElement.removeEventListener('dblclick', onDblClick); + + videoElement.parentNode.removeChild(videoElement); + } + + var dlg = videoDialog; + if (dlg) { + + videoDialog = null; + + dlg.parentNode.removeChild(dlg); + } + }; + function onEnded() { - destroyCustomTrack(this), htmlMediaHelper.onEndedInternal(self, this, onError) + + destroyCustomTrack(this); + htmlMediaHelper.onEndedInternal(self, this, onError); } function onTimeUpdate(e) { + + // Get the player position + the transcoding offset var time = this.currentTime; - time && !self._timeUpdated && (self._timeUpdated = !0, ensureValidVideo(this)), self._currentTime = time; - var currentPlayOptions = self._currentPlayOptions; - if (currentPlayOptions) { - var timeMs = 1e3 * time; - timeMs += (currentPlayOptions.transcodingOffsetTicks || 0) / 1e4, updateSubtitleText(timeMs) + + if (time && !self._timeUpdated) { + self._timeUpdated = true; + ensureValidVideo(this); } - events.trigger(self, "timeupdate") + + self._currentTime = time; + + var currentPlayOptions = self._currentPlayOptions; + // Not sure yet how this is coming up null since we never null it out, but it is causing app crashes + if (currentPlayOptions) { + var timeMs = time * 1000; + timeMs += ((currentPlayOptions.transcodingOffsetTicks || 0) / 10000); + updateSubtitleText(timeMs); + } + + events.trigger(self, 'timeupdate'); } function onVolumeChange() { - htmlMediaHelper.saveVolume(this.volume), events.trigger(self, "volumechange") + + htmlMediaHelper.saveVolume(this.volume); + events.trigger(self, 'volumechange'); } function onNavigatedToOsd() { - var dlg = videoDialog; - dlg && (dlg.classList.remove("videoPlayerContainer-withBackdrop"), dlg.classList.remove("videoPlayerContainer-onTop"), onStartedAndNavigatedToOsd()) - } + var dlg = videoDialog; + if (dlg) { + dlg.classList.remove('videoPlayerContainer-withBackdrop'); + dlg.classList.remove('videoPlayerContainer-onTop'); + + onStartedAndNavigatedToOsd(); + } + } function onStartedAndNavigatedToOsd() { - setCurrentTrackElement(subtitleTrackIndexToSetOnPlaying), null != audioTrackIndexToSetOnPlaying && self.canSetAudioStreamIndex() && self.setAudioStreamIndex(audioTrackIndexToSetOnPlaying) + + // If this causes a failure during navigation we end up in an awkward UI state + setCurrentTrackElement(subtitleTrackIndexToSetOnPlaying); + + if (audioTrackIndexToSetOnPlaying != null && self.canSetAudioStreamIndex()) { + self.setAudioStreamIndex(audioTrackIndexToSetOnPlaying); + } } function onPlaying(e) { - self._started || (self._started = !0, this.removeAttribute("controls"), loading.hide(), htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks), self._currentPlayOptions.fullscreen ? appRouter.showVideoOsd().then(onNavigatedToOsd) : (appRouter.setTransparency("backdrop"), videoDialog.classList.remove("videoPlayerContainer-withBackdrop"), videoDialog.classList.remove("videoPlayerContainer-onTop"), onStartedAndNavigatedToOsd())), events.trigger(self, "playing") + + if (!self._started) { + self._started = true; + this.removeAttribute('controls'); + + loading.hide(); + + htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks); + + if (self._currentPlayOptions.fullscreen) { + + appRouter.showVideoOsd().then(onNavigatedToOsd); + + } else { + appRouter.setTransparency('backdrop'); + videoDialog.classList.remove('videoPlayerContainer-withBackdrop'); + videoDialog.classList.remove('videoPlayerContainer-onTop'); + + onStartedAndNavigatedToOsd(); + } + } + events.trigger(self, 'playing'); } function onPlay(e) { - events.trigger(self, "unpause") + + events.trigger(self, 'unpause'); } function ensureValidVideo(elem) { - if (elem === self._mediaElement && 0 === elem.videoWidth && 0 === elem.videoHeight) { - var mediaSource = (self._currentPlayOptions || {}).mediaSource; - if (!mediaSource || mediaSource.RunTimeTicks) return void htmlMediaHelper.onErrorInternal(self, "mediadecodeerror") + if (elem !== self._mediaElement) { + return; } + + if (elem.videoWidth === 0 && elem.videoHeight === 0) { + + var mediaSource = (self._currentPlayOptions || {}).mediaSource; + + // Only trigger this if there is media info + // Avoid triggering in situations where it might not actually have a video stream (audio only live tv channel) + if (!mediaSource || mediaSource.RunTimeTicks) { + htmlMediaHelper.onErrorInternal(self, 'mediadecodeerror'); + return; + } + } + + //if (elem.audioTracks && !elem.audioTracks.length) { + // htmlMediaHelper.onErrorInternal(self, 'mediadecodeerror'); + //} } function onClick() { - events.trigger(self, "click") + events.trigger(self, 'click'); } function onDblClick() { - events.trigger(self, "dblclick") + events.trigger(self, 'dblclick'); } function onPause() { - events.trigger(self, "pause") + events.trigger(self, 'pause'); } function onError() { - var errorCode = this.error ? this.error.code || 0 : 0, - errorMessage = this.error ? this.error.message || "" : ""; - console.log("Media element error: " + errorCode.toString() + " " + errorMessage); + + var errorCode = this.error ? (this.error.code || 0) : 0; + var errorMessage = this.error ? (this.error.message || '') : ''; + console.log('Media element error: ' + errorCode.toString() + ' ' + errorMessage); + var type; + switch (errorCode) { case 1: + // MEDIA_ERR_ABORTED + // This will trigger when changing media while something is playing return; case 2: - type = "network"; + // MEDIA_ERR_NETWORK + type = 'network'; break; case 3: - if (self._hlsPlayer) return void htmlMediaHelper.handleHlsJsMediaError(self); - type = "mediadecodeerror"; + // MEDIA_ERR_DECODE + if (self._hlsPlayer) { + htmlMediaHelper.handleHlsJsMediaError(self); + return; + } else { + type = 'mediadecodeerror'; + } break; case 4: - type = "medianotsupported"; + // MEDIA_ERR_SRC_NOT_SUPPORTED + type = 'medianotsupported'; break; default: - return + // seeing cases where Edge is firing error events with no error code + // example is start playing something, then immediately change src to something else + return; } - htmlMediaHelper.onErrorInternal(self, type) + + htmlMediaHelper.onErrorInternal(self, type); } function destroyCustomTrack(videoElement) { - if (self._resizeObserver && (self._resizeObserver.disconnect(), self._resizeObserver = null), videoSubtitlesElem) { - var subtitlesContainer = videoSubtitlesElem.parentNode; - subtitlesContainer && tryRemoveElement(subtitlesContainer), videoSubtitlesElem = null + + if (self._resizeObserver) { + self._resizeObserver.disconnect(); + self._resizeObserver = null; } - if (currentTrackEvents = null, videoElement) - for (var allTracks = videoElement.textTracks || [], i = 0; i < allTracks.length; i++) { - var currentTrack = allTracks[i]; - 1 !== currentTrack.label.indexOf("manualTrack") && (currentTrack.mode = "disabled") + + if (videoSubtitlesElem) { + var subtitlesContainer = videoSubtitlesElem.parentNode; + if (subtitlesContainer) { + tryRemoveElement(subtitlesContainer); } - customTrackIndex = -1, currentClock = null, self._currentAspectRatio = null; + videoSubtitlesElem = null; + } + + currentTrackEvents = null; + + if (videoElement) { + var allTracks = videoElement.textTracks || []; // get list of tracks + for (var i = 0; i < allTracks.length; i++) { + + var currentTrack = allTracks[i]; + + if (currentTrack.label.indexOf('manualTrack') !== -1) { + currentTrack.mode = 'disabled'; + } + } + } + + customTrackIndex = -1; + currentClock = null; + self._currentAspectRatio = null; + var renderer = currentAssRenderer; - renderer && renderer.setEnabled(!1), currentAssRenderer = null + if (renderer) { + renderer.setEnabled(false); + } + currentAssRenderer = null; } + self.destroyCustomTrack = destroyCustomTrack; + function fetchSubtitlesUwp(track, item) { - return Windows.Storage.StorageFile.getFileFromPathAsync(track.Path).then(function(storageFile) { - return Windows.Storage.FileIO.readTextAsync(storageFile).then(function(text) { - return JSON.parse(text) - }) - }) + + return Windows.Storage.StorageFile.getFileFromPathAsync(track.Path).then(function (storageFile) { + + return Windows.Storage.FileIO.readTextAsync(storageFile).then(function (text) { + return JSON.parse(text); + }); + }); + } function fetchSubtitles(track, item) { - return window.Windows && itemHelper.isLocalItem(item) ? fetchSubtitlesUwp(track, item) : new Promise(function(resolve, reject) { - var xhr = new XMLHttpRequest, - url = getTextTrackUrl(track, item, ".js"); - xhr.open("GET", url, !0), xhr.onload = function(e) { - resolve(JSON.parse(this.response)) - }, xhr.onerror = reject, xhr.send() - }) + + if (window.Windows && itemHelper.isLocalItem(item)) { + return fetchSubtitlesUwp(track, item); + } + + return new Promise(function (resolve, reject) { + + var xhr = new XMLHttpRequest(); + + var url = getTextTrackUrl(track, item, '.js'); + + xhr.open('GET', url, true); + + xhr.onload = function (e) { + resolve(JSON.parse(this.response)); + }; + + xhr.onerror = reject; + + xhr.send(); + }); } function setTrackForCustomDisplay(videoElement, track) { - if (!track) return void destroyCustomTrack(videoElement); - if (customTrackIndex !== track.Index) { - var item = self._currentPlayOptions.item; - destroyCustomTrack(videoElement), customTrackIndex = track.Index, renderTracksEvents(videoElement, track, item), lastCustomTrackMs = 0 + + if (!track) { + destroyCustomTrack(videoElement); + return; } + + // if already playing thids track, skip + if (customTrackIndex === track.Index) { + return; + } + + var item = self._currentPlayOptions.item; + + destroyCustomTrack(videoElement); + customTrackIndex = track.Index; + renderTracksEvents(videoElement, track, item); + lastCustomTrackMs = 0; } function renderWithLibjass(videoElement, track, item) { + var rendererSettings = {}; - browser.ps4 ? rendererSettings.enableSvg = !1 : (browser.edge || browser.msie) && (rendererSettings.enableSvg = !1), rendererSettings.enableSvg = !1, require(["libjass", "ResizeObserver"], function(libjass, ResizeObserver) { - libjass.ASS.fromUrl(getTextTrackUrl(track, item)).then(function(ass) { - var clock = new libjass.renderers.ManualClock; + + if (browser.ps4) { + // Text outlines are not rendering very well + rendererSettings.enableSvg = false; + } + else if (browser.edge || browser.msie) { + // svg not rendering at all + rendererSettings.enableSvg = false; + } + + // probably safer to just disable everywhere + rendererSettings.enableSvg = false; + + require(['libjass', 'ResizeObserver'], function (libjass, ResizeObserver) { + + libjass.ASS.fromUrl(getTextTrackUrl(track, item)).then(function (ass) { + + var clock = new libjass.renderers.ManualClock(); currentClock = clock; + + // Create a DefaultRenderer using the video element and the ASS object var renderer = new libjass.renderers.WebRenderer(ass, clock, videoElement.parentNode, rendererSettings); - currentAssRenderer = renderer, renderer.addEventListener("ready", function() { + + currentAssRenderer = renderer; + + renderer.addEventListener("ready", function () { try { - renderer.resize(videoElement.offsetWidth, videoElement.offsetHeight, 0, 0), self._resizeObserver || (self._resizeObserver = new ResizeObserver(onVideoResize, {}), self._resizeObserver.observe(videoElement)) - } catch (ex) {} - }) - }, function() { - htmlMediaHelper.onErrorInternal(self, "mediadecodeerror") - }) - }) + renderer.resize(videoElement.offsetWidth, videoElement.offsetHeight, 0, 0); + + if (!self._resizeObserver) { + self._resizeObserver = new ResizeObserver(onVideoResize, {}); + self._resizeObserver.observe(videoElement); + } + //clock.pause(); + } catch (ex) { + //alert(ex); + } + }); + }, function () { + htmlMediaHelper.onErrorInternal(self, 'mediadecodeerror'); + }); + }); } function onVideoResize() { - browser.iOS ? setTimeout(resetVideoRendererSize, 500) : resetVideoRendererSize() + + if (browser.iOS) { + + // with wkwebview, the new sizes will be delayed for about 500ms + setTimeout(resetVideoRendererSize, 500); + } else { + resetVideoRendererSize(); + } } function resetVideoRendererSize() { var renderer = currentAssRenderer; if (renderer) { - var videoElement = self._mediaElement, - width = videoElement.offsetWidth, - height = videoElement.offsetHeight; - console.log("videoElement resized: " + width + "x" + height), renderer.resize(width, height, 0, 0) + var videoElement = self._mediaElement; + var width = videoElement.offsetWidth; + var height = videoElement.offsetHeight; + console.log('videoElement resized: ' + width + 'x' + height); + renderer.resize(width, height, 0, 0); } } function requiresCustomSubtitlesElement() { - if (browser.ps4) return !0; - if (browser.firefox || browser.web0s) return !0; - if (browser.edge) return !0; + + // after a system update, ps4 isn't showing anything when creating a track element dynamically + // going to have to do it ourselves + if (browser.ps4) { + return true; + } + + // This is unfortunate, but we're unable to remove the textTrack that gets added via addTextTrack + if (browser.firefox || browser.web0s) { + return true; + } + + if (browser.edge) { + return true; + } + if (browser.iOS) { var userAgent = navigator.userAgent.toLowerCase(); - if ((-1 !== userAgent.indexOf("os 9") || -1 !== userAgent.indexOf("os 8")) && -1 === userAgent.indexOf("safari")) return !0 + // works in the browser but not the native app + if ((userAgent.indexOf('os 9') !== -1 || userAgent.indexOf('os 8') !== -1) && userAgent.indexOf('safari') === -1) { + return true; + } } - return !1 + + return false; } function renderSubtitlesWithCustomElement(videoElement, track, item) { - fetchSubtitles(track, item).then(function(data) { + + fetchSubtitles(track, item).then(function (data) { if (!videoSubtitlesElem) { - var subtitlesContainer = document.createElement("div"); - subtitlesContainer.classList.add("videoSubtitles"), subtitlesContainer.innerHTML = '
', videoSubtitlesElem = subtitlesContainer.querySelector(".videoSubtitlesInner"), setSubtitleAppearance(subtitlesContainer, videoSubtitlesElem), videoElement.parentNode.appendChild(subtitlesContainer), currentTrackEvents = data.TrackEvents + var subtitlesContainer = document.createElement('div'); + subtitlesContainer.classList.add('videoSubtitles'); + subtitlesContainer.innerHTML = '
'; + videoSubtitlesElem = subtitlesContainer.querySelector('.videoSubtitlesInner'); + setSubtitleAppearance(subtitlesContainer, videoSubtitlesElem); + videoElement.parentNode.appendChild(subtitlesContainer); + currentTrackEvents = data.TrackEvents; } - }) + }); } function setSubtitleAppearance(elem, innerElem) { - require(["userSettings", "subtitleAppearanceHelper"], function(userSettings, subtitleAppearanceHelper) { + + require(['userSettings', 'subtitleAppearanceHelper'], function (userSettings, subtitleAppearanceHelper) { + subtitleAppearanceHelper.applyStyles({ + text: innerElem, window: elem - }, userSettings.getSubtitleAppearanceSettings()) - }) + + }, userSettings.getSubtitleAppearanceSettings()); + }); } function getCueCss(appearance, selector) { - var html = selector + "::cue {"; - return html += appearance.text.map(function(s) { - return s.name + ":" + s.value + "!important;" - }).join(""), html += "}" + + var html = selector + '::cue {'; + + html += appearance.text.map(function (s) { + + return s.name + ':' + s.value + '!important;'; + + }).join(''); + + html += '}'; + + return html; } function setCueAppearance() { - require(["userSettings", "subtitleAppearanceHelper"], function(userSettings, subtitleAppearanceHelper) { - var elementId = self.id + "-cuestyle", - styleElem = document.querySelector("#" + elementId); - styleElem || (styleElem = document.createElement("style"), styleElem.id = elementId, styleElem.type = "text/css", document.getElementsByTagName("head")[0].appendChild(styleElem)), styleElem.innerHTML = getCueCss(subtitleAppearanceHelper.getStyles(userSettings.getSubtitleAppearanceSettings(), !0), ".htmlvideoplayer") - }) + + require(['userSettings', 'subtitleAppearanceHelper'], function (userSettings, subtitleAppearanceHelper) { + + var elementId = self.id + '-cuestyle'; + + var styleElem = document.querySelector('#' + elementId); + if (!styleElem) { + styleElem = document.createElement('style'); + styleElem.id = elementId; + styleElem.type = 'text/css'; + document.getElementsByTagName('head')[0].appendChild(styleElem); + } + + styleElem.innerHTML = getCueCss(subtitleAppearanceHelper.getStyles(userSettings.getSubtitleAppearanceSettings(), true), '.htmlvideoplayer'); + }); } function renderTracksEvents(videoElement, track, item) { + if (!itemHelper.isLocalItem(item) || track.IsExternal) { - var format = (track.Codec || "").toLowerCase(); - if ("ssa" === format || "ass" === format) return void renderWithLibjass(videoElement, track, item); - if (requiresCustomSubtitlesElement()) return void renderSubtitlesWithCustomElement(videoElement, track, item) + var format = (track.Codec || '').toLowerCase(); + if (format === 'ssa' || format === 'ass') { + // libjass is needed here + renderWithLibjass(videoElement, track, item); + return; + } + + if (requiresCustomSubtitlesElement()) { + renderSubtitlesWithCustomElement(videoElement, track, item); + return; + } } - for (var trackElement = null, expectedId = "manualTrack" + track.Index, allTracks = videoElement.textTracks, i = 0; i < allTracks.length; i++) { + + var trackElement = null; + var expectedId = 'manualTrack' + track.Index; + + var allTracks = videoElement.textTracks; // get list of tracks + for (var i = 0; i < allTracks.length; i++) { + var currentTrack = allTracks[i]; + if (currentTrack.label === expectedId) { trackElement = currentTrack; - break + break; + } else { + currentTrack.mode = 'disabled'; } - currentTrack.mode = "disabled" } - trackElement ? trackElement.mode = "showing" : (trackElement = videoElement.addTextTrack("subtitles", "manualTrack" + track.Index, track.Language || "und"), fetchSubtitles(track, item).then(function(data) { - console.log("downloaded " + data.TrackEvents.length + " track events"), data.TrackEvents.forEach(function(trackEvent) { - var trackCueObject = window.VTTCue || window.TextTrackCue, - cue = new trackCueObject(trackEvent.StartPositionTicks / 1e7, trackEvent.EndPositionTicks / 1e7, normalizeTrackEventText(trackEvent.Text)); - trackElement.addCue(cue) - }), trackElement.mode = "showing" - })) + + if (!trackElement) { + trackElement = videoElement.addTextTrack('subtitles', 'manualTrack' + track.Index, track.Language || 'und'); + + // download the track json + fetchSubtitles(track, item).then(function (data) { + + // show in ui + console.log('downloaded ' + data.TrackEvents.length + ' track events'); + // add some cues to show the text + // in safari, the cues need to be added before setting the track mode to showing + data.TrackEvents.forEach(function (trackEvent) { + + var trackCueObject = window.VTTCue || window.TextTrackCue; + var cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text)); + + trackElement.addCue(cue); + }); + trackElement.mode = 'showing'; + }); + } else { + trackElement.mode = 'showing'; + } } function updateSubtitleText(timeMs) { + var clock = currentClock; - if (clock) try { - clock.seek(timeMs / 1e3) - } catch (err) { - console.log("Error in libjass: " + err) - } else { - var trackEvents = currentTrackEvents, - subtitleTextElement = videoSubtitlesElem; - if (trackEvents && subtitleTextElement) { - for (var selectedTrackEvent, ticks = 1e4 * timeMs, i = 0; i < trackEvents.length; i++) { - var currentTrackEvent = trackEvents[i]; - if (currentTrackEvent.StartPositionTicks <= ticks && currentTrackEvent.EndPositionTicks >= ticks) { - selectedTrackEvent = currentTrackEvent; - break - } + if (clock) { + try { + clock.seek(timeMs / 1000); + } catch (err) { + console.log('Error in libjass: ' + err); + } + return; + } + + var trackEvents = currentTrackEvents; + var subtitleTextElement = videoSubtitlesElem; + + if (trackEvents && subtitleTextElement) { + var ticks = timeMs * 10000; + var selectedTrackEvent; + for (var i = 0; i < trackEvents.length; i++) { + + var currentTrackEvent = trackEvents[i]; + if (currentTrackEvent.StartPositionTicks <= ticks && currentTrackEvent.EndPositionTicks >= ticks) { + selectedTrackEvent = currentTrackEvent; + break; } - selectedTrackEvent && selectedTrackEvent.Text ? (subtitleTextElement.innerHTML = normalizeTrackEventText(selectedTrackEvent.Text), subtitleTextElement.classList.remove("hide")) : subtitleTextElement.classList.add("hide") + } + + if (selectedTrackEvent && selectedTrackEvent.Text) { + + subtitleTextElement.innerHTML = normalizeTrackEventText(selectedTrackEvent.Text); + subtitleTextElement.classList.remove('hide'); + + } else { + subtitleTextElement.classList.add('hide'); } } } function setCurrentTrackElement(streamIndex) { - console.log("Setting new text track index to: " + streamIndex); - var mediaStreamTextTracks = getMediaStreamTextTracks(self._currentPlayOptions.mediaSource), - track = -1 === streamIndex ? null : mediaStreamTextTracks.filter(function(t) { - return t.Index === streamIndex - })[0]; - enableNativeTrackSupport(self._currentSrc, track) ? (setTrackForCustomDisplay(self._mediaElement, null), -1 !== streamIndex && setCueAppearance()) : (setTrackForCustomDisplay(self._mediaElement, track), streamIndex = -1, track = null); - for (var expectedId = "textTrack" + streamIndex, trackIndex = -1 !== streamIndex && track ? mediaStreamTextTracks.indexOf(track) : -1, modes = ["disabled", "showing", "hidden"], allTracks = self._mediaElement.textTracks, i = 0; i < allTracks.length; i++) { - var currentTrack = allTracks[i]; - console.log("currentTrack id: " + currentTrack.id); - var mode; - if (console.log("expectedId: " + expectedId + "--currentTrack.Id:" + currentTrack.id), browser.msie || browser.edge) mode = trackIndex === i ? 1 : 0; - else { - if (-1 !== currentTrack.label.indexOf("manualTrack")) continue; - mode = currentTrack.id === expectedId ? 1 : 0 + + console.log('Setting new text track index to: ' + streamIndex); + + var mediaStreamTextTracks = getMediaStreamTextTracks(self._currentPlayOptions.mediaSource); + + var track = streamIndex === -1 ? null : mediaStreamTextTracks.filter(function (t) { + return t.Index === streamIndex; + })[0]; + + if (enableNativeTrackSupport(self._currentSrc, track)) { + + setTrackForCustomDisplay(self._mediaElement, null); + + if (streamIndex !== -1) { + setCueAppearance(); } - console.log("Setting track " + i + " mode to: " + mode), currentTrack.mode = modes[mode] + + } else { + setTrackForCustomDisplay(self._mediaElement, track); + + // null these out to disable the player's native display (handled below) + streamIndex = -1; + track = null; + } + + var expectedId = 'textTrack' + streamIndex; + var trackIndex = streamIndex === -1 || !track ? -1 : mediaStreamTextTracks.indexOf(track); + var modes = ['disabled', 'showing', 'hidden']; + + var allTracks = self._mediaElement.textTracks; // get list of tracks + for (var i = 0; i < allTracks.length; i++) { + + var currentTrack = allTracks[i]; + + console.log('currentTrack id: ' + currentTrack.id); + + var mode; + + console.log('expectedId: ' + expectedId + '--currentTrack.Id:' + currentTrack.id); + + // IE doesn't support track id + if (browser.msie || browser.edge) { + if (trackIndex === i) { + mode = 1; // show this track + } else { + mode = 0; // hide all other tracks + } + } else { + + if (currentTrack.label.indexOf('manualTrack') !== -1) { + continue; + } + if (currentTrack.id === expectedId) { + mode = 1; // show this track + } else { + mode = 0; // hide all other tracks + } + } + + console.log('Setting track ' + i + ' mode to: ' + mode); + + currentTrack.mode = modes[mode]; + } + } + + function updateTextStreamUrls(startPositionTicks) { + + if (!supportsTextTracks()) { + return; + } + + var allTracks = self._mediaElement.textTracks; // get list of tracks + var i; + var track; + + for (i = 0; i < allTracks.length; i++) { + + track = allTracks[i]; + + // This throws an error in IE, but is fine in chrome + // In IE it's not necessary anyway because changing the src seems to be enough + try { + while (track.cues.length) { + track.removeCue(track.cues[0]); + } + } catch (e) { + console.log('Error removing cue from textTrack'); + } + } + + var tracks = self._mediaElement.querySelectorAll('track'); + for (i = 0; i < tracks.length; i++) { + + track = tracks[i]; + + track.src = replaceQueryString(track.src, 'startPositionTicks', startPositionTicks); } } function createMediaElement(options) { - return (browser.tv || browser.iOS || browser.mobile) && (options.backdropUrl = null), new Promise(function(resolve, reject) { - var dlg = document.querySelector(".videoPlayerContainer"); - dlg ? (options.backdropUrl && (dlg.classList.add("videoPlayerContainer-withBackdrop"), dlg.style.backgroundImage = "url('" + options.backdropUrl + "')"), resolve(dlg.querySelector("video"))) : require(["css!./style"], function() { - loading.show(); - var dlg = document.createElement("div"); - dlg.classList.add("videoPlayerContainer"), options.backdropUrl && (dlg.classList.add("videoPlayerContainer-withBackdrop"), dlg.style.backgroundImage = "url('" + options.backdropUrl + "')"), options.fullscreen && dlg.classList.add("videoPlayerContainer-onTop"); - var html = "", - cssClass = "htmlvideoplayer"; - browser.chromecast || (cssClass += " htmlvideoplayer-moveupsubtitles"), appHost.supports("htmlvideoautoplay") ? html += '
"), html += "
", html += "
", html += "" + + var tagName = layoutManager.tv ? 'button' : 'div'; + var enableFooterButtons = !layoutManager.tv; + + var html = ''; + + var cssClass = "card scalableCard imageEditorCard"; + var cardBoxCssClass = 'cardBox visualCardBox'; + + var shape = 'backdrop'; + if (imageType === "Backdrop" || imageType === "Art" || imageType === "Thumb" || imageType === "Logo") { + shape = 'backdrop'; + } + else if (imageType === "Banner") { + shape = 'banner'; + } + else if (imageType === "Disc") { + shape = 'square'; + } + else { + + if (currentItemType === "Episode") { + shape = 'backdrop'; + } + else if (currentItemType === "MusicAlbum" || currentItemType === "MusicArtist") { + shape = 'square'; + } + else { + shape = 'portrait'; + } + } + + cssClass += ' ' + shape + 'Card ' + shape + 'Card-scalable'; + if (tagName === 'button') { + cssClass += ' btnImageCard'; + + if (layoutManager.tv && !browser.slow) { + cardBoxCssClass += ' cardBox-focustransform'; + } + + if (layoutManager.tv) { + cardBoxCssClass += ' card-focuscontent cardBox-withfocuscontent'; + } + + html += ''; + html += '
'; + } + + html += '
'; + // end footer + + html += '
'; + //html += '
'; + + html += ''; + + return html; } function initEditor(page, apiClient) { - page.querySelector("#selectBrowsableImageType").addEventListener("change", function() { - browsableImageType = this.value, browsableImageStartIndex = 0, selectedProvider = null, reloadBrowsableImages(page, apiClient) - }), page.querySelector("#selectImageProvider").addEventListener("change", function() { - browsableImageStartIndex = 0, selectedProvider = this.value, reloadBrowsableImages(page, apiClient) - }), page.querySelector("#chkAllLanguages").addEventListener("change", function() { - browsableImageStartIndex = 0, reloadBrowsableImages(page, apiClient) - }), page.addEventListener("click", function(e) { - var btnDownloadRemoteImage = parentWithClass(e.target, "btnDownloadRemoteImage"); + + page.querySelector('#selectBrowsableImageType').addEventListener('change', function () { + browsableImageType = this.value; + browsableImageStartIndex = 0; + selectedProvider = null; + + reloadBrowsableImages(page, apiClient); + }); + + page.querySelector('#selectImageProvider').addEventListener('change', function () { + + browsableImageStartIndex = 0; + selectedProvider = this.value; + + reloadBrowsableImages(page, apiClient); + }); + + page.querySelector('#chkAllLanguages').addEventListener('change', function () { + + browsableImageStartIndex = 0; + + reloadBrowsableImages(page, apiClient); + }); + + page.addEventListener('click', function (e) { + + var btnDownloadRemoteImage = parentWithClass(e.target, 'btnDownloadRemoteImage'); if (btnDownloadRemoteImage) { - var card = parentWithClass(btnDownloadRemoteImage, "card"); - return void downloadRemoteImage(page, apiClient, card.getAttribute("data-imageurl"), card.getAttribute("data-imagetype"), card.getAttribute("data-imageprovider")) + var card = parentWithClass(btnDownloadRemoteImage, 'card'); + downloadRemoteImage(page, apiClient, card.getAttribute('data-imageurl'), card.getAttribute('data-imagetype'), card.getAttribute('data-imageprovider')); + return; } - var btnImageCard = parentWithClass(e.target, "btnImageCard"); - btnImageCard && downloadRemoteImage(page, apiClient, btnImageCard.getAttribute("data-imageurl"), btnImageCard.getAttribute("data-imagetype"), btnImageCard.getAttribute("data-imageprovider")) - }) + + var btnImageCard = parentWithClass(e.target, 'btnImageCard'); + if (btnImageCard) { + downloadRemoteImage(page, apiClient, btnImageCard.getAttribute('data-imageurl'), btnImageCard.getAttribute('data-imagetype'), btnImageCard.getAttribute('data-imageprovider')); + } + }); } function showEditor(itemId, serverId, itemType) { - loading.show(), require(["text!./imagedownloader.template.html"], function(template) { + + loading.show(); + + require(['text!./imagedownloader.template.html'], function (template) { + var apiClient = connectionManager.getApiClient(serverId); - currentItemId = itemId, currentItemType = itemType; + + currentItemId = itemId; + currentItemType = itemType; + var dialogOptions = { - removeOnClose: !0 + removeOnClose: true }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "fullscreen-border"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'fullscreen-border'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.innerHTML = globalize.translateDocument(template, "sharedcomponents"), layoutManager.tv && scrollHelper.centerFocus.on(dlg, !1), dlg.addEventListener("close", onDialogClosed), dialogHelper.open(dlg); - var editorContent = dlg.querySelector(".formDialogContent"); - initEditor(editorContent, apiClient), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), reloadBrowsableImages(editorContent, apiClient) - }) + + dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg, false); + } + + // Has to be assigned a z-index after the call to .open() + dlg.addEventListener('close', onDialogClosed); + + dialogHelper.open(dlg); + + var editorContent = dlg.querySelector('.formDialogContent'); + initEditor(editorContent, apiClient); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + + reloadBrowsableImages(editorContent, apiClient); + }); } function onDialogClosed() { + var dlg = this; - layoutManager.tv && scrollHelper.centerFocus.off(dlg, !1), loading.hide(), hasChanges ? currentResolve() : currentReject() - } - var currentItemId, currentItemType, currentResolve, currentReject, selectedProvider, hasChanges = !1, - browsableImagePageSize = browser.slow ? 6 : 30, - browsableImageStartIndex = 0, - browsableImageType = "Primary"; - return { - show: function(itemId, serverId, itemType, imageType) { - return new Promise(function(resolve, reject) { - currentResolve = resolve, currentReject = reject, hasChanges = !1, browsableImageStartIndex = 0, browsableImageType = imageType || "Primary", selectedProvider = null, showEditor(itemId, serverId, itemType) - }) + + if (layoutManager.tv) { + scrollHelper.centerFocus.off(dlg, false); + } + + loading.hide(); + if (hasChanges) { + currentResolve(); + } else { + currentReject(); } } + + return { + show: function (itemId, serverId, itemType, imageType) { + + return new Promise(function (resolve, reject) { + + currentResolve = resolve; + currentReject = reject; + hasChanges = false; + browsableImageStartIndex = 0; + browsableImageType = imageType || 'Primary'; + selectedProvider = null; + + showEditor(itemId, serverId, itemType); + }); + } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/imageeditor/imageeditor.css b/src/bower_components/emby-webcomponents/imageeditor/imageeditor.css index 46c5ecd743..724b9ffb0f 100644 --- a/src/bower_components/emby-webcomponents/imageeditor/imageeditor.css +++ b/src/bower_components/emby-webcomponents/imageeditor/imageeditor.css @@ -1,13 +1,9 @@ -.imageEditor-buttons { - display: -webkit-box; - display: -webkit-flex; +.imageEditor-buttons { display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - margin: 1em 0 + margin: 1em 0 1em; } .first-imageEditor-buttons { - margin-top: 2em + margin-top: 2em; } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/imageeditor/imageeditor.js b/src/bower_components/emby-webcomponents/imageeditor/imageeditor.js index 98f527901e..339e7a0f32 100644 --- a/src/bower_components/emby-webcomponents/imageeditor/imageeditor.js +++ b/src/bower_components/emby-webcomponents/imageeditor/imageeditor.js @@ -1,220 +1,513 @@ -define(["dialogHelper", "connectionManager", "loading", "dom", "layoutManager", "focusManager", "globalize", "scrollHelper", "imageLoader", "require", "browser", "apphost", "cardStyle", "formDialogStyle", "emby-button", "paper-icon-button-light", "css!./imageeditor"], function(dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require, browser, appHost) { - "use strict"; +define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', 'focusManager', 'globalize', 'scrollHelper', 'imageLoader', 'require', 'browser', 'apphost', 'cardStyle', 'formDialogStyle', 'emby-button', 'paper-icon-button-light', 'css!./imageeditor'], function (dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require, browser, appHost) { + 'use strict'; + + var currentItem; + var hasChanges = false; function getBaseRemoteOptions() { + var options = {}; - return options.itemId = currentItem.Id, options + + options.itemId = currentItem.Id; + + return options; } function reload(page, item, focusContext) { + loading.show(); + var apiClient; - item ? (apiClient = connectionManager.getApiClient(item.ServerId), reloadItem(page, item, apiClient, focusContext)) : (apiClient = connectionManager.getApiClient(currentItem.ServerId), apiClient.getItem(apiClient.getCurrentUserId(), currentItem.Id).then(function(item) { - reloadItem(page, item, apiClient, focusContext) - })) + + if (item) { + apiClient = connectionManager.getApiClient(item.ServerId); + reloadItem(page, item, apiClient, focusContext); + } + else { + + apiClient = connectionManager.getApiClient(currentItem.ServerId); + apiClient.getItem(apiClient.getCurrentUserId(), currentItem.Id).then(function (item) { + reloadItem(page, item, apiClient, focusContext); + }); + } } function addListeners(container, className, eventName, fn) { - container.addEventListener(eventName, function(e) { + + container.addEventListener(eventName, function (e) { var elem = dom.parentWithClass(e.target, className); - elem && fn.call(elem, e) - }) + if (elem) { + fn.call(elem, e); + } + }); } function reloadItem(page, item, apiClient, focusContext) { - currentItem = item, apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function(providers) { - for (var btnBrowseAllImages = page.querySelectorAll(".btnBrowseAllImages"), i = 0, length = btnBrowseAllImages.length; i < length; i++) providers.length ? btnBrowseAllImages[i].classList.remove("hide") : btnBrowseAllImages[i].classList.add("hide"); - apiClient.getItemImageInfos(currentItem.Id).then(function(imageInfos) { - renderStandardImages(page, apiClient, item, imageInfos, providers), renderBackdrops(page, apiClient, item, imageInfos, providers), renderScreenshots(page, apiClient, item, imageInfos, providers), loading.hide(), layoutManager.tv && focusManager.autoFocus(focusContext || page) - }) - }) + + currentItem = item; + + apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function (providers) { + + var btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages'); + for (var i = 0, length = btnBrowseAllImages.length; i < length; i++) { + + if (providers.length) { + btnBrowseAllImages[i].classList.remove('hide'); + } else { + btnBrowseAllImages[i].classList.add('hide'); + } + } + + + apiClient.getItemImageInfos(currentItem.Id).then(function (imageInfos) { + + renderStandardImages(page, apiClient, item, imageInfos, providers); + renderBackdrops(page, apiClient, item, imageInfos, providers); + renderScreenshots(page, apiClient, item, imageInfos, providers); + loading.hide(); + + if (layoutManager.tv) { + focusManager.autoFocus((focusContext || page)); + } + }); + }); } function getImageUrl(item, apiClient, type, index, options) { - return options = options || {}, options.type = type, options.index = index, options.tag = "Backdrop" === type ? item.BackdropImageTags[index] : "Screenshot" === type ? item.ScreenshotImageTags[index] : "Primary" === type ? item.PrimaryImageTag || item.ImageTags[type] : item.ImageTags[type], apiClient.getScaledImageUrl(item.Id || item.ItemId, options) + + options = options || {}; + options.type = type; + options.index = index; + + if (type === 'Backdrop') { + options.tag = item.BackdropImageTags[index]; + } else if (type === 'Screenshot') { + options.tag = item.ScreenshotImageTags[index]; + } else if (type === 'Primary') { + options.tag = item.PrimaryImageTag || item.ImageTags[type]; + } else { + options.tag = item.ImageTags[type]; + } + + // For search hints + return apiClient.getScaledImageUrl(item.Id || item.ItemId, options); } function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) { - var html = "", - cssClass = "card scalableCard imageEditorCard", - cardBoxCssClass = "cardBox visualCardBox"; - return cssClass += " backdropCard backdropCard-scalable", "button" === tagName ? (cssClass += " btnImageCard", layoutManager.tv && !browser.slow && (cardBoxCssClass += " cardBox-focustransform"), layoutManager.tv && (cardBoxCssClass += " card-focuscontent cardBox-withfocuscontent"), html += '' : '', html += index < numImages - 1 ? '' : '') : imageProviders.length && (html += ''), html += '', html += "
"), html += "
", html += "
", html += "" + + var html = ''; + + var cssClass = "card scalableCard imageEditorCard"; + var cardBoxCssClass = 'cardBox visualCardBox'; + + cssClass += " backdropCard backdropCard-scalable"; + + if (tagName === 'button') { + cssClass += ' btnImageCard'; + + if (layoutManager.tv && !browser.slow) { + cardBoxCssClass += ' cardBox-focustransform'; + } + + if (layoutManager.tv) { + cardBoxCssClass += ' card-focuscontent cardBox-withfocuscontent'; + } + + html += ''; + } else { + html += ''; + } + + if (index < numImages - 1) { + html += ''; + } else { + html += ''; + } + } + else { + if (imageProviders.length) { + html += ''; + } + } + + html += ''; + html += '
'; + } + + html += '
'; + html += '
'; + html += ''; + + return html; } function deleteImage(context, itemId, type, index, apiClient, enableConfirmation) { - var afterConfirm = function() { - apiClient.deleteItemImage(itemId, type, index).then(function() { - hasChanges = !0, reload(context) - }) + + var afterConfirm = function () { + apiClient.deleteItemImage(itemId, type, index).then(function () { + + hasChanges = true; + reload(context); + + }); }; - if (!enableConfirmation) return void afterConfirm(); - require(["confirm"], function(confirm) { + + if (!enableConfirmation) { + afterConfirm(); + return; + } + + require(['confirm'], function (confirm) { + confirm({ - text: globalize.translate("sharedcomponents#ConfirmDeleteImage"), - confirmText: globalize.translate("sharedcomponents#Delete"), - primary: "cancel" - }).then(afterConfirm) - }) + + text: globalize.translate('sharedcomponents#ConfirmDeleteImage'), + confirmText: globalize.translate('sharedcomponents#Delete'), + primary: 'cancel' + + }).then(afterConfirm); + }); } function moveImage(context, apiClient, itemId, type, index, newIndex, focusContext) { - apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function() { - hasChanges = !0, reload(context, null, focusContext) - }, function() { - require(["alert"], function(alert) { - alert(globalize.translate("sharedcomponents#DefaultErrorMessage")) - }) - }) + + apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function () { + + hasChanges = true; + reload(context, null, focusContext); + }, function () { + + require(['alert'], function (alert) { + alert(globalize.translate('sharedcomponents#DefaultErrorMessage')); + }); + }); } function renderImages(page, item, apiClient, images, imageProviders, elem) { - var html = "", - imageSize = 300, - windowSize = dom.getWindowSize(); - windowSize.innerWidth >= 1280 && (imageSize = Math.round(windowSize.innerWidth / 4)); - for (var tagName = layoutManager.tv ? "button" : "div", enableFooterButtons = !layoutManager.tv, i = 0, length = images.length; i < length; i++) { - html += getCardHtml(images[i], i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) + + var html = ''; + + var imageSize = 300; + var windowSize = dom.getWindowSize(); + if (windowSize.innerWidth >= 1280) { + imageSize = Math.round(windowSize.innerWidth / 4); } - elem.innerHTML = html, imageLoader.lazyChildren(elem) + + var tagName = layoutManager.tv ? 'button' : 'div'; + var enableFooterButtons = !layoutManager.tv; + + for (var i = 0, length = images.length; i < length; i++) { + + var image = images[i]; + + html += getCardHtml(image, i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons); + } + + elem.innerHTML = html; + imageLoader.lazyChildren(elem); } function renderStandardImages(page, apiClient, item, imageInfos, imageProviders) { - renderImages(page, item, apiClient, imageInfos.filter(function(i) { - return "Screenshot" !== i.ImageType && "Backdrop" !== i.ImageType && "Chapter" !== i.ImageType - }), imageProviders, page.querySelector("#images")) + + var images = imageInfos.filter(function (i) { + return i.ImageType !== "Screenshot" && i.ImageType !== "Backdrop" && i.ImageType !== "Chapter"; + }); + + renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#images')); } function renderBackdrops(page, apiClient, item, imageInfos, imageProviders) { - var images = imageInfos.filter(function(i) { - return "Backdrop" === i.ImageType - }).sort(function(a, b) { - return a.ImageIndex - b.ImageIndex + + var images = imageInfos.filter(function (i) { + return i.ImageType === "Backdrop"; + + }).sort(function (a, b) { + return a.ImageIndex - b.ImageIndex; }); - images.length ? (page.querySelector("#backdropsContainer", page).classList.remove("hide"), renderImages(page, item, apiClient, images, imageProviders, page.querySelector("#backdrops"))) : page.querySelector("#backdropsContainer", page).classList.add("hide") + + if (images.length) { + page.querySelector('#backdropsContainer', page).classList.remove('hide'); + renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#backdrops')); + } else { + page.querySelector('#backdropsContainer', page).classList.add('hide'); + } } function renderScreenshots(page, apiClient, item, imageInfos, imageProviders) { - var images = imageInfos.filter(function(i) { - return "Screenshot" === i.ImageType - }).sort(function(a, b) { - return a.ImageIndex - b.ImageIndex + + var images = imageInfos.filter(function (i) { + return i.ImageType === "Screenshot"; + + }).sort(function (a, b) { + return a.ImageIndex - b.ImageIndex; }); - images.length ? (page.querySelector("#screenshotsContainer", page).classList.remove("hide"), renderImages(page, item, apiClient, images, imageProviders, page.querySelector("#screenshots"))) : page.querySelector("#screenshotsContainer", page).classList.add("hide") + + if (images.length) { + page.querySelector('#screenshotsContainer', page).classList.remove('hide'); + renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#screenshots')); + } else { + page.querySelector('#screenshotsContainer', page).classList.add('hide'); + } } function showImageDownloader(page, imageType) { - require(["imageDownloader"], function(ImageDownloader) { - ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function() { - hasChanges = !0, reload(page) - }) - }) + + require(['imageDownloader'], function (ImageDownloader) { + + ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function () { + + hasChanges = true; + reload(page); + }); + + }); } function showActionSheet(context, imageCard) { - var itemId = imageCard.getAttribute("data-id"), - serverId = imageCard.getAttribute("data-serverid"), - apiClient = connectionManager.getApiClient(serverId), - type = imageCard.getAttribute("data-imagetype"), - index = parseInt(imageCard.getAttribute("data-index")), - providerCount = parseInt(imageCard.getAttribute("data-providers")), - numImages = parseInt(imageCard.getAttribute("data-numimages")); - require(["actionsheet"], function(actionSheet) { + + var itemId = imageCard.getAttribute('data-id'); + var serverId = imageCard.getAttribute('data-serverid'); + var apiClient = connectionManager.getApiClient(serverId); + + var type = imageCard.getAttribute('data-imagetype'); + var index = parseInt(imageCard.getAttribute('data-index')); + var providerCount = parseInt(imageCard.getAttribute('data-providers')); + var numImages = parseInt(imageCard.getAttribute('data-numimages')); + + require(['actionsheet'], function (actionSheet) { + var commands = []; + commands.push({ - name: globalize.translate("sharedcomponents#Delete"), - id: "delete" - }), "Backdrop" !== type && "Screenshot" !== type || (index > 0 && commands.push({ - name: globalize.translate("sharedcomponents#MoveLeft"), - id: "moveleft" - }), index < numImages - 1 && commands.push({ - name: globalize.translate("sharedcomponents#MoveRight"), - id: "moveright" - })), providerCount && commands.push({ - name: globalize.translate("sharedcomponents#Search"), - id: "search" - }), actionSheet.show({ + name: globalize.translate('sharedcomponents#Delete'), + id: 'delete' + }); + + if (type === 'Backdrop' || type === 'Screenshot') { + if (index > 0) { + commands.push({ + name: globalize.translate('sharedcomponents#MoveLeft'), + id: 'moveleft' + }); + } + + if (index < numImages - 1) { + commands.push({ + name: globalize.translate('sharedcomponents#MoveRight'), + id: 'moveright' + }); + } + } + + if (providerCount) { + commands.push({ + name: globalize.translate('sharedcomponents#Search'), + id: 'search' + }); + } + + actionSheet.show({ + items: commands, positionTo: imageCard - }).then(function(id) { + + }).then(function (id) { + switch (id) { - case "delete": - deleteImage(context, itemId, type, index, apiClient, !1); + + case 'delete': + deleteImage(context, itemId, type, index, apiClient, false); break; - case "search": + case 'search': showImageDownloader(context, type); break; - case "moveleft": - moveImage(context, apiClient, itemId, type, index, index - 1, dom.parentWithClass(imageCard, "itemsContainer")); + case 'moveleft': + moveImage(context, apiClient, itemId, type, index, index - 1, dom.parentWithClass(imageCard, 'itemsContainer')); + break; + case 'moveright': + moveImage(context, apiClient, itemId, type, index, index + 1, dom.parentWithClass(imageCard, 'itemsContainer')); + break; + default: break; - case "moveright": - moveImage(context, apiClient, itemId, type, index, index + 1, dom.parentWithClass(imageCard, "itemsContainer")) } - }) - }) + + }); + }); } function initEditor(context, options) { - for (var uploadButtons = context.querySelectorAll(".btnOpenUploadMenu"), isFileInputSupported = appHost.supports("fileinput"), i = 0, length = uploadButtons.length; i < length; i++) isFileInputSupported ? uploadButtons[i].classList.remove("hide") : uploadButtons[i].classList.add("hide"); - addListeners(context, "btnOpenUploadMenu", "click", function() { - var imageType = this.getAttribute("data-imagetype"); - require(["imageUploader"], function(imageUploader) { + + var uploadButtons = context.querySelectorAll('.btnOpenUploadMenu'); + var isFileInputSupported = appHost.supports('fileinput'); + for (var i = 0, length = uploadButtons.length; i < length; i++) { + if (isFileInputSupported) { + uploadButtons[i].classList.remove('hide'); + } else { + uploadButtons[i].classList.add('hide'); + } + } + + addListeners(context, 'btnOpenUploadMenu', 'click', function () { + var imageType = this.getAttribute('data-imagetype'); + + require(['imageUploader'], function (imageUploader) { + imageUploader.show({ + theme: options.theme, imageType: imageType, itemId: currentItem.Id, serverId: currentItem.ServerId - }).then(function(hasChanged) { - hasChanged && (hasChanges = !0, reload(context)) - }) - }) - }), addListeners(context, "btnSearchImages", "click", function() { - showImageDownloader(context, this.getAttribute("data-imagetype")) - }), addListeners(context, "btnBrowseAllImages", "click", function() { - showImageDownloader(context, this.getAttribute("data-imagetype") || "Primary") - }), addListeners(context, "btnImageCard", "click", function() { - showActionSheet(context, this) - }), addListeners(context, "btnDeleteImage", "click", function() { - var type = this.getAttribute("data-imagetype"), - index = this.getAttribute("data-index"); - index = "null" === index ? null : parseInt(index); + + }).then(function (hasChanged) { + + if (hasChanged) { + hasChanges = true; + reload(context); + } + }); + }); + }); + + addListeners(context, 'btnSearchImages', 'click', function () { + showImageDownloader(context, this.getAttribute('data-imagetype')); + }); + + addListeners(context, 'btnBrowseAllImages', 'click', function () { + showImageDownloader(context, this.getAttribute('data-imagetype') || 'Primary'); + }); + + addListeners(context, 'btnImageCard', 'click', function () { + showActionSheet(context, this); + }); + + addListeners(context, 'btnDeleteImage', 'click', function () { + var type = this.getAttribute('data-imagetype'); + var index = this.getAttribute('data-index'); + index = index === "null" ? null : parseInt(index); var apiClient = connectionManager.getApiClient(currentItem.ServerId); - deleteImage(context, currentItem.Id, type, index, apiClient, !0) - }), addListeners(context, "btnMoveImage", "click", function() { - var type = this.getAttribute("data-imagetype"), - index = this.getAttribute("data-index"), - newIndex = this.getAttribute("data-newindex"), - apiClient = connectionManager.getApiClient(currentItem.ServerId); - moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, "itemsContainer")) - }) + deleteImage(context, currentItem.Id, type, index, apiClient, true); + }); + + addListeners(context, 'btnMoveImage', 'click', function () { + var type = this.getAttribute('data-imagetype'); + var index = this.getAttribute('data-index'); + var newIndex = this.getAttribute('data-newindex'); + var apiClient = connectionManager.getApiClient(currentItem.ServerId); + moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, 'itemsContainer')); + }); } function showEditor(options, resolve, reject) { - var itemId = options.itemId, - serverId = options.serverId; - loading.show(), require(["text!./imageeditor.template.html"], function(template) { + + var itemId = options.itemId; + var serverId = options.serverId; + + loading.show(); + + require(['text!./imageeditor.template.html'], function (template) { var apiClient = connectionManager.getApiClient(serverId); - apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(item) { + apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { + var dialogOptions = { - removeOnClose: !0 + removeOnClose: true }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "fullscreen-border"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'fullscreen-border'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateDocument(template, "sharedcomponents"), layoutManager.tv && scrollHelper.centerFocus.on(dlg, !1), initEditor(dlg, options), dlg.addEventListener("close", function() { - layoutManager.tv && scrollHelper.centerFocus.off(dlg, !1), loading.hide(), hasChanges ? resolve() : reject() - }), dialogHelper.open(dlg), reload(dlg, item), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }) - }) - }) + + dlg.classList.add('formDialog'); + + dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg, false); + } + + initEditor(dlg, options); + + // Has to be assigned a z-index after the call to .open() + dlg.addEventListener('close', function () { + + if (layoutManager.tv) { + scrollHelper.centerFocus.off(dlg, false); + } + + loading.hide(); + + if (hasChanges) { + resolve(); + } else { + reject(); + } + }); + + dialogHelper.open(dlg); + + reload(dlg, item); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + }); + }); } - var currentItem, hasChanges = !1; + return { - show: function(options) { - return new Promise(function(resolve, reject) { - hasChanges = !1, showEditor(options, resolve, reject) - }) + show: function (options) { + + return new Promise(function (resolve, reject) { + + hasChanges = false; + + showEditor(options, resolve, reject); + }); } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/images/basicimagefetcher.js b/src/bower_components/emby-webcomponents/images/basicimagefetcher.js index 7ba86474e0..54d3ef7502 100644 --- a/src/bower_components/emby-webcomponents/images/basicimagefetcher.js +++ b/src/bower_components/emby-webcomponents/images/basicimagefetcher.js @@ -1,18 +1,38 @@ -define(["dom"], function(dom) { - "use strict"; +define(['dom'], function (dom) { + 'use strict'; function loadImage(elem, url) { - return elem ? "IMG" !== elem.tagName ? (elem.style.backgroundImage = "url('" + url + "')", Promise.resolve()) : loadImageIntoImg(elem, url) : Promise.reject("elem cannot be null") + + if (!elem) { + return Promise.reject('elem cannot be null'); + } + + if (elem.tagName !== "IMG") { + + elem.style.backgroundImage = "url('" + url + "')"; + return Promise.resolve(); + + //return loadImageIntoImg(document.createElement('img'), url).then(function () { + // elem.style.backgroundImage = "url('" + url + "')"; + // return Promise.resolve(); + //}); + + } + return loadImageIntoImg(elem, url); } function loadImageIntoImg(elem, url) { - return new Promise(function(resolve, reject) { - dom.addEventListener(elem, "load", resolve, { - once: !0 - }), elem.setAttribute("src", url) - }) + return new Promise(function (resolve, reject) { + + dom.addEventListener(elem, 'load', resolve, { + once: true + }); + elem.setAttribute("src", url); + }); } + return { loadImage: loadImage - } + }; + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/images/imagehelper.js b/src/bower_components/emby-webcomponents/images/imagehelper.js index ddcf5b7ba7..106de3a696 100644 --- a/src/bower_components/emby-webcomponents/images/imagehelper.js +++ b/src/bower_components/emby-webcomponents/images/imagehelper.js @@ -1,82 +1,255 @@ -define(["lazyLoader", "imageFetcher", "layoutManager", "browser", "appSettings", "require", "css!./style"], function(lazyLoader, imageFetcher, layoutManager, browser, appSettings, require) { - "use strict"; +define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', 'require', 'css!./style'], function (lazyLoader, imageFetcher, layoutManager, browser, appSettings, require) { + 'use strict'; + + var requestIdleCallback = window.requestIdleCallback || function (fn) { + fn(); + }; + + var self = {}; + + // seeing slow performance with firefox + var enableFade = false; function fillImage(elem, source, enableEffects) { - if (!elem) throw new Error("elem cannot be null"); - source || (source = elem.getAttribute("data-src")), source && fillImageElement(elem, source, enableEffects) + + if (!elem) { + throw new Error('elem cannot be null'); + } + + if (!source) { + source = elem.getAttribute('data-src'); + } + + if (!source) { + return; + } + + fillImageElement(elem, source, enableEffects); } function fillImageElement(elem, source, enableEffects) { - imageFetcher.loadImage(elem, source).then(function() { - enableFade && !1 !== enableEffects && fadeIn(elem), elem.removeAttribute("data-src") - }) + imageFetcher.loadImage(elem, source).then(function () { + + var fillingVibrant = false;//fillVibrant(elem, source); + + if (enableFade && enableEffects !== false && !fillingVibrant) { + fadeIn(elem); + } + + elem.removeAttribute("data-src"); + }); + } + + function fillVibrant(img, url, canvas, canvasContext) { + + var vibrantElement = img.getAttribute('data-vibrant'); + if (!vibrantElement) { + return false; + } + + if (window.Vibrant) { + fillVibrantOnLoaded(img, url, vibrantElement, canvas, canvasContext); + return true; + } + + require(['vibrant'], function () { + fillVibrantOnLoaded(img, url, vibrantElement, canvas, canvasContext); + }); + return true; + } + + function fillVibrantOnLoaded(img, url, vibrantElement) { + + vibrantElement = document.getElementById(vibrantElement); + if (!vibrantElement) { + return; + } + + requestIdleCallback(function () { + + //var now = new Date().getTime(); + getVibrantInfoFromElement(img, url).then(function (vibrantInfo) { + + var swatch = vibrantInfo.split('|'); + //console.log('vibrant took ' + (new Date().getTime() - now) + 'ms'); + if (swatch.length) { + + var index = 0; + var style = vibrantElement.style; + style.backgroundColor = swatch[index]; + style.color = swatch[index + 1]; + + var classList = vibrantElement.classList; + + if (classList.contains('cardFooter')) { + classList.add('cardFooter-vibrant'); + } else { + classList.add('vibrant'); + } + } + }); + }); + /* + * Results into: + * Vibrant #7a4426 + * Muted #7b9eae + * DarkVibrant #348945 + * DarkMuted #141414 + * LightVibrant #f3ccb4 + */ } function getVibrantInfoFromElement(elem, url) { - return new Promise(function(resolve, reject) { - require(["vibrant"], function() { - if ("IMG" === elem.tagName) return void resolve(getVibrantInfo(elem, url)); - var img = new Image; - img.onload = function() { - resolve(getVibrantInfo(img, url)) - }, img.src = 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("://"); - url = parts[parts.length - 1], url = url.substring(url.indexOf("/") + 1), url = url.split("?")[0]; - return "vibrant31" + url + + var parts = url.split('://'); + url = parts[parts.length - 1]; + + url = url.substring(url.indexOf('/') + 1); + + url = url.split('?')[0]; + + var cacheKey = 'vibrant31'; + //cacheKey = 'vibrant' + new Date().getTime(); + return cacheKey + url; } function getCachedVibrantInfo(url) { - return appSettings.get(getSettingsKey(url)) + + return appSettings.get(getSettingsKey(url)); } function getVibrantInfo(img, url) { + var value = getCachedVibrantInfo(url); - if (value) return value; - var vibrant = new Vibrant(img), - swatches = vibrant.swatches(); - return value = "", value += getSwatchString(swatches.DarkVibrant), appSettings.set(getSettingsKey(url), value), value + if (value) { + return value; + } + + var vibrant = new Vibrant(img); + var swatches = vibrant.swatches(); + + value = ''; + var swatch = swatches.DarkVibrant; + value += getSwatchString(swatch); + + appSettings.set(getSettingsKey(url), value); + + return value; } function getSwatchString(swatch) { - return swatch ? swatch.getHex() + "|" + swatch.getBodyTextColor() + "|" + swatch.getTitleTextColor() : "||" + + if (swatch) { + return swatch.getHex() + '|' + swatch.getBodyTextColor() + '|' + swatch.getTitleTextColor(); + } + return '||'; } function fadeIn(elem) { - elem.classList.add("lazy-image-fadein") + + var cssClass = 'lazy-image-fadein'; + + elem.classList.add(cssClass); } function lazyChildren(elem) { - lazyLoader.lazyChildren(elem, fillImage) + + lazyLoader.lazyChildren(elem, fillImage); } function getPrimaryImageAspectRatio(items) { - for (var values = [], i = 0, length = items.length; i < length; i++) { + + var values = []; + + for (var i = 0, length = items.length; i < length; i++) { + var ratio = items[i].PrimaryImageAspectRatio || 0; - ratio && (values[values.length] = ratio) + + if (!ratio) { + continue; + } + + values[values.length] = ratio; } - if (!values.length) return null; - values.sort(function(a, b) { - return a - b - }); - var result, half = Math.floor(values.length / 2); - result = values.length % 2 ? values[half] : (values[half - 1] + values[half]) / 2; - if (Math.abs(2 / 3 - result) <= .15) return 2 / 3; - if (Math.abs(16 / 9 - result) <= .2) return 16 / 9; - if (Math.abs(1 - result) <= .15) return 1; - return Math.abs(4 / 3 - result) <= .15 ? 4 / 3 : result + + if (!values.length) { + return null; + } + + // Use the median + values.sort(function (a, b) { return a - b; }); + + var half = Math.floor(values.length / 2); + + var result; + + if (values.length % 2) { + result = values[half]; + } + else { + result = (values[half - 1] + values[half]) / 2.0; + } + + // If really close to 2:3 (poster image), just return 2:3 + var aspect2x3 = 2 / 3; + if (Math.abs(aspect2x3 - result) <= 0.15) { + return aspect2x3; + } + + // If really close to 16:9 (episode image), just return 16:9 + var aspect16x9 = 16 / 9; + if (Math.abs(aspect16x9 - result) <= 0.2) { + return aspect16x9; + } + + // If really close to 1 (square image), just return 1 + if (Math.abs(1 - result) <= 0.15) { + return 1; + } + + // If really close to 4:3 (poster image), just return 2:3 + var aspect4x3 = 4 / 3; + if (Math.abs(aspect4x3 - result) <= 0.15) { + return aspect4x3; + } + + return result; } function fillImages(elems) { + for (var i = 0, length = elems.length; i < length; i++) { - fillImage(elems[0]) + var elem = elems[0]; + fillImage(elem); } } - var self = (window.requestIdleCallback, {}), - enableFade = !1; - return self.fillImages = fillImages, self.lazyImage = fillImage, self.lazyChildren = lazyChildren, self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio, self.getCachedVibrantInfo = getCachedVibrantInfo, self.getVibrantInfoFromElement = getVibrantInfoFromElement, self + + self.fillImages = fillImages; + self.lazyImage = fillImage; + self.lazyChildren = lazyChildren; + self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio; + self.getCachedVibrantInfo = getCachedVibrantInfo; + self.getVibrantInfoFromElement = getVibrantInfoFromElement; + + return self; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/images/style.css b/src/bower_components/emby-webcomponents/images/style.css index e2fb63c310..5cf39c1e4b 100644 --- a/src/bower_components/emby-webcomponents/images/style.css +++ b/src/bower_components/emby-webcomponents/images/style.css @@ -1,61 +1,47 @@ .lazy-image-fadein { - -webkit-animation: lazy-image-fadein 330ms ease-in normal both; - animation: lazy-image-fadein 330ms ease-in normal both + animation: lazy-image-fadein 330ms ease-in normal both; } .lazy-image-fadein-fast { - -webkit-animation: lazy-image-fadein 160ms ease-in normal both; - animation: lazy-image-fadein 160ms ease-in normal both -} - -@-webkit-keyframes lazy-image-fadein { - from { - opacity: 0 - } - - to { - opacity: 1 - } + animation: lazy-image-fadein 160ms ease-in normal both; } @keyframes lazy-image-fadein { from { - opacity: 0 + opacity: 0; } to { - opacity: 1 + opacity: 1; } } .lazy-image-fadein { opacity: 0; -webkit-animation-duration: .8s; + -moz-animation-duration: .8s; + -o-animation-duration: .8s; animation-duration: .8s; -webkit-animation-name: popInAnimation; + -moz-animation-name: popInAnimation; + -o-animation-name: popInAnimation; animation-name: popInAnimation; -webkit-animation-fill-mode: forwards; + -moz-animation-fill-mode: forwards; + -o-animation-fill-mode: forwards; animation-fill-mode: forwards; - -webkit-animation-timing-function: cubic-bezier(0, 0, .5, 1); - animation-timing-function: cubic-bezier(0, 0, .5, 1) -} - -@-webkit-keyframes popInAnimation { - 0% { - opacity: 0 - } - - 100% { - opacity: 1 - } + -webkit-animation-timing-function: cubic-bezier(0,0,.5,1); + -moz-animation-timing-function: cubic-bezier(0,0,.5,1); + -o-animation-timing-function: cubic-bezier(0,0,.5,1); + animation-timing-function: cubic-bezier(0,0,.5,1); } @keyframes popInAnimation { 0% { - opacity: 0 + opacity: 0; } 100% { - opacity: 1 + opacity: 1; } } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/imageuploader/imageuploader.js b/src/bower_components/emby-webcomponents/imageuploader/imageuploader.js index 87a0d643ba..5d6c0f8745 100644 --- a/src/bower_components/emby-webcomponents/imageuploader/imageuploader.js +++ b/src/bower_components/emby-webcomponents/imageuploader/imageuploader.js @@ -1,80 +1,177 @@ -define(["dialogHelper", "connectionManager", "dom", "loading", "scrollHelper", "layoutManager", "globalize", "require", "emby-button", "emby-select", "formDialogStyle", "css!./style"], function(dialogHelper, connectionManager, dom, loading, scrollHelper, layoutManager, globalize, require) { - "use strict"; +define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', 'layoutManager', 'globalize', 'require', 'emby-button', 'emby-select', 'formDialogStyle', 'css!./style'], function (dialogHelper, connectionManager, dom, loading, scrollHelper, layoutManager, globalize, require) { + 'use strict'; + + var currentItemId; + var currentServerId; + var currentFile; + var hasChanges = false; function onFileReaderError(evt) { - switch (loading.hide(), evt.target.error.code) { + + loading.hide(); + + switch (evt.target.error.code) { case evt.target.error.NOT_FOUND_ERR: - require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#MessageFileReadError")) + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#MessageFileReadError')); }); break; case evt.target.error.ABORT_ERR: - break; + break; // noop default: - require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#MessageFileReadError")) - }) + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#MessageFileReadError')); + }); + break; } } function setFiles(page, files) { + var file = files[0]; - if (!file || !file.type.match("image.*")) return page.querySelector("#imageOutput").innerHTML = "", page.querySelector("#fldUpload").classList.add("hide"), void(currentFile = null); + + if (!file || !file.type.match('image.*')) { + page.querySelector('#imageOutput').innerHTML = ''; + page.querySelector('#fldUpload').classList.add('hide'); + currentFile = null; + return; + } + currentFile = file; - var reader = new FileReader; - reader.onerror = onFileReaderError, reader.onloadstart = function() { - page.querySelector("#fldUpload").classList.add("hide") - }, reader.onabort = function() { - loading.hide(), console.log("File read cancelled") - }, reader.onload = function(theFile) { - return function(e) { - var html = [''].join(""); - page.querySelector("#imageOutput").innerHTML = html, page.querySelector("#fldUpload").classList.remove("hide") - } - }(file), reader.readAsDataURL(file) + + var reader = new FileReader(); + + reader.onerror = onFileReaderError; + reader.onloadstart = function () { + page.querySelector('#fldUpload').classList.add('hide'); + }; + reader.onabort = function () { + loading.hide(); + console.log('File read cancelled'); + }; + + // Closure to capture the file information. + reader.onload = (function (theFile) { + return function (e) { + + // Render thumbnail. + var html = [''].join(''); + + page.querySelector('#imageOutput').innerHTML = html; + page.querySelector('#fldUpload').classList.remove('hide'); + }; + })(file); + + // Read in the image file as a data URL. + reader.readAsDataURL(file); } function onSubmit(e) { + var file = currentFile; - if (!file) return !1; - if ("image/png" !== file.type && "image/jpeg" !== file.type && "image/jpeg" !== file.type) return !1; + + if (!file) { + return false; + } + + if (file.type !== "image/png" && file.type !== "image/jpeg" && file.type !== "image/jpeg") { + return false; + } + loading.show(); - var dlg = dom.parentWithClass(this, "dialog"), - imageType = dlg.querySelector("#selectImageType").value; - return connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(function() { - dlg.querySelector("#uploadImage").value = "", loading.hide(), hasChanges = !0, dialogHelper.close(dlg) - }), e.preventDefault(), !1 + + var dlg = dom.parentWithClass(this, 'dialog'); + + var imageType = dlg.querySelector('#selectImageType').value; + + connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(function () { + + dlg.querySelector('#uploadImage').value = ''; + + loading.hide(); + hasChanges = true; + dialogHelper.close(dlg); + }); + + e.preventDefault(); + return false; } function initEditor(page) { - page.querySelector("form").addEventListener("submit", onSubmit), page.querySelector("#uploadImage").addEventListener("change", function() { - setFiles(page, this.files) - }), page.querySelector(".btnBrowse").addEventListener("click", function() { - page.querySelector("#uploadImage").click() - }) + + page.querySelector('form').addEventListener('submit', onSubmit); + + page.querySelector('#uploadImage').addEventListener("change", function () { + setFiles(page, this.files); + }); + + page.querySelector('.btnBrowse').addEventListener("click", function () { + page.querySelector('#uploadImage').click(); + }); } function showEditor(options, resolve, reject) { - options = options || {}, require(["text!./imageuploader.template.html"], function(template) { - currentItemId = options.itemId, currentServerId = options.serverId; + + options = options || {}; + + require(['text!./imageuploader.template.html'], function (template) { + + currentItemId = options.itemId; + currentServerId = options.serverId; + var dialogOptions = { - removeOnClose: !0 + removeOnClose: true }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "fullscreen-border"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'fullscreen-border'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateDocument(template, "sharedcomponents"), layoutManager.tv && scrollHelper.centerFocus.on(dlg, !1), dlg.addEventListener("close", function() { - layoutManager.tv && scrollHelper.centerFocus.off(dlg, !1), loading.hide(), resolve(hasChanges) - }), dialogHelper.open(dlg), initEditor(dlg), dlg.querySelector("#selectImageType").value = options.imageType || "Primary", dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }) - }) + + dlg.classList.add('formDialog'); + + dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg, false); + } + + // Has to be assigned a z-index after the call to .open() + dlg.addEventListener('close', function () { + + if (layoutManager.tv) { + scrollHelper.centerFocus.off(dlg, false); + } + + loading.hide(); + resolve(hasChanges); + }); + + dialogHelper.open(dlg); + + initEditor(dlg); + + dlg.querySelector('#selectImageType').value = options.imageType || 'Primary'; + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + }); } - var currentItemId, currentServerId, currentFile, hasChanges = !1; + return { - show: function(options) { - return new Promise(function(resolve, reject) { - hasChanges = !1, showEditor(options, resolve, reject) - }) + show: function (options) { + + return new Promise(function (resolve, reject) { + + hasChanges = false; + + showEditor(options, resolve, reject); + }); } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/imageuploader/style.css b/src/bower_components/emby-webcomponents/imageuploader/style.css index 2ac0954235..e259b4b7dc 100644 --- a/src/bower_components/emby-webcomponents/imageuploader/style.css +++ b/src/bower_components/emby-webcomponents/imageuploader/style.css @@ -1,17 +1,11 @@ -.imageEditor-dropZone { +.imageEditor-dropZone { border: .2em dashed currentcolor; - -webkit-border-radius: .25em; border-radius: .25em; + /* padding: 1.6em; */ text-align: center; position: relative; height: 12em; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center + justify-content: center; } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/indicators/indicators.css b/src/bower_components/emby-webcomponents/indicators/indicators.css index 28999f2fe0..c2d089e1af 100644 --- a/src/bower_components/emby-webcomponents/indicators/indicators.css +++ b/src/bower_components/emby-webcomponents/indicators/indicators.css @@ -1,125 +1,96 @@ .itemProgressBar { background: #333; - background: rgba(51, 51, 51, .8); + background: rgba(51,51,51,.8); position: relative; - height: .28em + height: .28em; } .itemProgressBarForeground { position: absolute; top: 0; left: 0; - bottom: 0 + bottom: 0; } .indicator { - -webkit-border-radius: 100em; border-radius: 100em; display: -webkit-flex; - display: -webkit-box; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; font-weight: 500; width: 2em; - height: 2em -} - -.countIndicator, -.playedIndicator { - -webkit-border-radius: 100em; - display: -webkit-flex; - display: -webkit-box; - -webkit-box-align: center; - -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2) + height: 2em; } .timerIndicator { - color: #CB272A + color: #CB272A; } .timerIndicator-inactive { - color: #888 + color: #888; } -.indicator+.indicator { - margin-left: .25em +.indicator + .indicator { + margin-left: .25em; } .indicatorIcon { width: auto; height: auto; - font-size: 1.6em + font-size: 1.6em; } .countIndicator { border-radius: 100em; + display: -webkit-flex; display: flex; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; font-weight: 500; color: #fff; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2); - font-size: 88% + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2); + font-size: 88%; } .playedIndicator { border-radius: 100em; + display: -webkit-flex; display: flex; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; color: #fff; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2); - font-size: 80% + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2); + font-size: 80%; } .videoIndicator { background: #444; - -webkit-border-radius: 100em; border-radius: 100em; display: -webkit-flex; - display: -webkit-box; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; color: #fff; - -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2); - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2); - font-size: 88% + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2); + font-size: 88%; } .syncIndicator { - -webkit-border-radius: 100em; - border-radius: 100em + border-radius: 100em; } .emptySyncIndicator { background: #ccc; - color: #333 + color: #333; } -.missingIndicator, -.unairedIndicator { - background: #c33; +.missingIndicator, .unairedIndicator { + background: #cc3333; padding: .25em .5em; - -webkit-border-radius: 100em; border-radius: 100em; color: #fff; font-size: 84%; font-weight: 500; - margin: 0 .25em + margin: 0 .25em; } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/indicators/indicators.js b/src/bower_components/emby-webcomponents/indicators/indicators.js index 41c3188aa2..3b6e6baf70 100644 --- a/src/bower_components/emby-webcomponents/indicators/indicators.js +++ b/src/bower_components/emby-webcomponents/indicators/indicators.js @@ -1,112 +1,274 @@ -define(["datetime", "itemHelper", "css!./indicators.css", "material-icons"], function(datetime, itemHelper) { - "use strict"; +define(['datetime', 'itemHelper', 'css!./indicators.css', 'material-icons'], function (datetime, itemHelper) { + 'use strict'; function enableProgressIndicator(item) { - return "Video" === item.MediaType && "TvChannel" !== item.Type || ("AudioBook" === item.Type || "AudioPodcast" === item.Type) + + if (item.MediaType === 'Video') { + if (item.Type !== 'TvChannel') { + return true; + } + } + + if (item.Type === 'AudioBook' || item.Type === 'AudioPodcast') { + return true; + } + + return false; } function getProgressHtml(pct, options) { - var containerClass = "itemProgressBar"; - return options && options.containerClass && (containerClass += " " + options.containerClass), '
' + + var containerClass = 'itemProgressBar'; + + if (options) { + if (options.containerClass) { + containerClass += ' ' + options.containerClass; + } + } + + return '
'; } function getAutoTimeProgressHtml(pct, options, isRecording, start, end) { - var containerClass = "itemProgressBar"; - options && options.containerClass && (containerClass += " " + options.containerClass); - var foregroundClass = "itemProgressBarForeground"; - return isRecording && (foregroundClass += " itemProgressBarForeground-recording"), '
' + + var containerClass = 'itemProgressBar'; + + if (options) { + if (options.containerClass) { + containerClass += ' ' + options.containerClass; + } + } + + var foregroundClass = 'itemProgressBarForeground'; + + if (isRecording) { + foregroundClass += ' itemProgressBarForeground-recording'; + } + + return '
'; } function getProgressBarHtml(item, options) { + var pct; - if (enableProgressIndicator(item) && "Recording" !== item.Type) { - var userData = options ? options.userData || item.UserData : item.UserData; - if (userData && (pct = userData.PlayedPercentage) && pct < 100) return getProgressHtml(pct, options) - } - if (("Program" === item.Type || "Timer" === item.Type || "Recording" === item.Type) && item.StartDate && item.EndDate) { - var startDate = 0, - endDate = 1; - try { - startDate = datetime.parseISO8601Date(item.StartDate).getTime() - } catch (err) {} - try { - endDate = datetime.parseISO8601Date(item.EndDate).getTime() - } catch (err) {} - if ((pct = ((new Date).getTime() - startDate) / (endDate - startDate) * 100) > 0 && pct < 100) { - return getAutoTimeProgressHtml(pct, options, "Timer" === item.Type || "Recording" === item.Type || item.TimerId, startDate, endDate) + + if (enableProgressIndicator(item) && item.Type !== "Recording") { + + var userData = options ? (options.userData || item.UserData) : item.UserData; + if (userData) { + pct = userData.PlayedPercentage; + + if (pct && pct < 100) { + + return getProgressHtml(pct, options); + } } } - return "" + + if ((item.Type === 'Program' || item.Type === 'Timer' || item.Type === 'Recording') && item.StartDate && item.EndDate) { + + var startDate = 0; + var endDate = 1; + + try { + + startDate = datetime.parseISO8601Date(item.StartDate).getTime(); + + } catch (err) { + } + + try { + + endDate = datetime.parseISO8601Date(item.EndDate).getTime(); + + } catch (err) { + } + + var now = new Date().getTime(); + var total = endDate - startDate; + pct = 100 * ((now - startDate) / total); + + if (pct > 0 && pct < 100) { + + var isRecording = item.Type === 'Timer' || item.Type === 'Recording' || item.TimerId; + + return getAutoTimeProgressHtml(pct, options, isRecording, startDate, endDate); + } + } + + return ''; } function enablePlayedIndicator(item) { - return itemHelper.canMarkPlayed(item) + + return itemHelper.canMarkPlayed(item); } function getPlayedIndicator(item) { + if (enablePlayedIndicator(item)) { + var userData = item.UserData || {}; - if (userData.UnplayedItemCount) return '
' + userData.UnplayedItemCount + "
"; - if (userData.PlayedPercentage && userData.PlayedPercentage >= 100 || userData.Played) return '
' + + if (userData.UnplayedItemCount) { + return '
' + userData.UnplayedItemCount + '
'; + } + + if (userData.PlayedPercentage && userData.PlayedPercentage >= 100 || (userData.Played)) { + return '
'; + } } - return "" + + return ''; } function getCountIndicatorHtml(count) { - return '
' + count + "
" + + return '
' + count + '
'; } function getChildCountIndicatorHtml(item, options) { + var minCount = 0; - return options && (minCount = options.minCount || minCount), item.ChildCount && item.ChildCount > minCount ? getCountIndicatorHtml(item.ChildCount) : "" + + if (options) { + minCount = options.minCount || minCount; + } + + if (item.ChildCount && item.ChildCount > minCount) { + return getCountIndicatorHtml(item.ChildCount); + } + + return ''; } function getTimerIndicator(item) { + var status; - if ("SeriesTimer" === item.Type) return ''; - if (item.TimerId || item.SeriesTimerId) status = item.Status || "Cancelled"; - else { - if ("Timer" !== item.Type) return ""; - status = item.Status + + if (item.Type === 'SeriesTimer') { + return ''; } - return item.SeriesTimerId ? "Cancelled" !== status ? '' : '' : '' + else if (item.TimerId || item.SeriesTimerId) { + + status = item.Status || 'Cancelled'; + } + else if (item.Type === 'Timer') { + + status = item.Status; + } + else { + return ''; + } + + if (item.SeriesTimerId) { + + if (status !== 'Cancelled') { + return ''; + } + + return ''; + } + + return ''; } function getSyncIndicator(item) { - return 100 === item.SyncPercent ? '
' : null != item.SyncPercent ? '
' : "" + + if (item.SyncPercent === 100) { + return '
'; + } else if (item.SyncPercent != null) { + return '
'; + } + + return ''; } function getTypeIndicator(item) { - return "Video" === item.Type ? '
' : "Folder" === item.Type || "PhotoAlbum" === item.Type ? '
' : "Photo" === item.Type ? '
' : "" + + if (item.Type === 'Video') { + + return '
'; + } + if (item.Type === 'Folder' || item.Type === 'PhotoAlbum') { + + return '
'; + } + if (item.Type === 'Photo') { + + return '
'; + //return '
'; + } + + return ''; } function getMissingIndicator(item) { - if ("Episode" === item.Type && "Virtual" === item.LocationType) { - if (item.PremiereDate) try { - if (datetime.parseISO8601Date(item.PremiereDate).getTime() > (new Date).getTime()) return '
Unaired
' - } catch (err) {} - return '
Missing
' + + if (item.Type === 'Episode' && item.LocationType === 'Virtual') { + + if (item.PremiereDate) { + try { + + var premiereDate = datetime.parseISO8601Date(item.PremiereDate).getTime(); + + if (premiereDate > new Date().getTime()) { + return '
Unaired
'; + } + + } catch (err) { + } + } + + return '
Missing
'; } - return "" + + return ''; } - function onAutoTimeProgress() { - var start = parseInt(this.getAttribute("data-starttime")), - end = parseInt(this.getAttribute("data-endtime")), - now = (new Date).getTime(), - total = end - start, - pct = (now - start) / total * 100; - pct = Math.min(100, pct), pct = Math.max(0, pct), this.querySelector(".itemProgressBarForeground").style.width = pct + "%" - } var ProgressBarPrototype = Object.create(HTMLDivElement.prototype); - return ProgressBarPrototype.attachedCallback = function() { - this.timeInterval && clearInterval(this.timeInterval), "time" === this.getAttribute("data-automode") && (this.timeInterval = setInterval(onAutoTimeProgress.bind(this), 6e4)) - }, ProgressBarPrototype.detachedCallback = function() { - this.timeInterval && (clearInterval(this.timeInterval), this.timeInterval = null) - }, document.registerElement("emby-progressbar", { + + function onAutoTimeProgress() { + + var start = parseInt(this.getAttribute('data-starttime')); + var end = parseInt(this.getAttribute('data-endtime')); + + var now = new Date().getTime(); + var total = end - start; + var pct = 100 * ((now - start) / total); + + pct = Math.min(100, pct); + pct = Math.max(0, pct); + + var itemProgressBarForeground = this.querySelector('.itemProgressBarForeground'); + itemProgressBarForeground.style.width = pct + '%'; + } + + ProgressBarPrototype.attachedCallback = function () { + + if (this.timeInterval) { + clearInterval(this.timeInterval); + } + + if (this.getAttribute('data-automode') === 'time') { + this.timeInterval = setInterval(onAutoTimeProgress.bind(this), 60000); + } + }; + + ProgressBarPrototype.detachedCallback = function () { + + if (this.timeInterval) { + clearInterval(this.timeInterval); + this.timeInterval = null; + } + }; + + document.registerElement('emby-progressbar', { prototype: ProgressBarPrototype, - extends: "div" - }), { + extends: 'div' + }); + + return { getProgressBarHtml: getProgressBarHtml, getPlayedIndicatorHtml: getPlayedIndicator, getChildCountIndicatorHtml: getChildCountIndicatorHtml, @@ -116,5 +278,5 @@ define(["datetime", "itemHelper", "css!./indicators.css", "material-icons"], fun getSyncIndicator: getSyncIndicator, getTypeIndicator: getTypeIndicator, getMissingIndicator: getMissingIndicator - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/input/api.js b/src/bower_components/emby-webcomponents/input/api.js index 13f0abc9ba..4cec8358cd 100644 --- a/src/bower_components/emby-webcomponents/input/api.js +++ b/src/bower_components/emby-webcomponents/input/api.js @@ -1,145 +1,245 @@ -define(["connectionManager", "playbackManager", "events", "inputManager", "focusManager", "appRouter"], function(connectionManager, playbackManager, events, inputManager, focusManager, appRouter) { - "use strict"; +define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focusManager', 'appRouter'], function (connectionManager, playbackManager, events, inputManager, focusManager, appRouter) { + 'use strict'; + + var serverNotifications = {}; function notifyApp() { - inputManager.notify() + + inputManager.notify(); } function displayMessage(cmd) { + var args = cmd.Arguments; - args.TimeoutMs ? require(["toast"], function(toast) { - toast({ - title: args.Header, - text: args.Text - }) - }) : require(["alert"], function(alert) { - alert({ - title: args.Header, - text: args.Text - }) - }) + + if (args.TimeoutMs) { + + require(['toast'], function (toast) { + toast({ title: args.Header, text: args.Text }); + }); + + } + else { + require(['alert'], function (alert) { + alert({ title: args.Header, text: args.Text }); + }); + } } function displayContent(cmd, apiClient) { - playbackManager.isPlayingLocally(["Video", "Book", "Game"]) || appRouter.showItem(cmd.Arguments.ItemId, apiClient.serverId()) + + if (!playbackManager.isPlayingLocally(['Video', 'Book', 'Game'])) { + appRouter.showItem(cmd.Arguments.ItemId, apiClient.serverId()); + } } function playTrailers(apiClient, itemId) { - apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(item) { - playbackManager.playTrailers(item) - }) + + apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { + + playbackManager.playTrailers(item); + }); } function processGeneralCommand(cmd, apiClient) { + + // Full list + // https://github.com/MediaBrowser/MediaBrowser/blob/master/MediaBrowser.Model/Session/GeneralCommand.cs#L23 + //console.log('Received command: ' + cmd.Name); + switch (cmd.Name) { - case "Select": - return void inputManager.trigger("select"); - case "Back": - return void inputManager.trigger("back"); - case "MoveUp": - return void inputManager.trigger("up"); - case "MoveDown": - return void inputManager.trigger("down"); - case "MoveLeft": - return void inputManager.trigger("left"); - case "MoveRight": - return void inputManager.trigger("right"); - case "PageUp": - return void inputManager.trigger("pageup"); - case "PageDown": - return void inputManager.trigger("pagedown"); - case "PlayTrailers": + + case 'Select': + inputManager.trigger('select'); + return; + case 'Back': + inputManager.trigger('back'); + return; + case 'MoveUp': + inputManager.trigger('up'); + return; + case 'MoveDown': + inputManager.trigger('down'); + return; + case 'MoveLeft': + inputManager.trigger('left'); + return; + case 'MoveRight': + inputManager.trigger('right'); + return; + case 'PageUp': + inputManager.trigger('pageup'); + return; + case 'PageDown': + inputManager.trigger('pagedown'); + return; + case 'PlayTrailers': playTrailers(apiClient, cmd.Arguments.ItemId); break; - case "SetRepeatMode": + case 'SetRepeatMode': playbackManager.setRepeatMode(cmd.Arguments.RepeatMode); break; - case "VolumeUp": - return void inputManager.trigger("volumeup"); - case "VolumeDown": - return void inputManager.trigger("volumedown"); - case "ChannelUp": - return void inputManager.trigger("channelup"); - case "ChannelDown": - return void inputManager.trigger("channeldown"); - case "Mute": - return void inputManager.trigger("mute"); - case "Unmute": - return void inputManager.trigger("unmute"); - case "ToggleMute": - return void inputManager.trigger("togglemute"); - case "SetVolume": - notifyApp(), playbackManager.setVolume(cmd.Arguments.Volume); + case 'VolumeUp': + inputManager.trigger('volumeup'); + return; + case 'VolumeDown': + inputManager.trigger('volumedown'); + return; + case 'ChannelUp': + inputManager.trigger('channelup'); + return; + case 'ChannelDown': + inputManager.trigger('channeldown'); + return; + case 'Mute': + inputManager.trigger('mute'); + return; + case 'Unmute': + inputManager.trigger('unmute'); + return; + case 'ToggleMute': + inputManager.trigger('togglemute'); + return; + case 'SetVolume': + notifyApp(); + playbackManager.setVolume(cmd.Arguments.Volume); break; - case "SetAudioStreamIndex": - notifyApp(), playbackManager.setAudioStreamIndex(parseInt(cmd.Arguments.Index)); + case 'SetAudioStreamIndex': + notifyApp(); + playbackManager.setAudioStreamIndex(parseInt(cmd.Arguments.Index)); break; - case "SetSubtitleStreamIndex": - notifyApp(), playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index)); + case 'SetSubtitleStreamIndex': + notifyApp(); + playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index)); break; - case "ToggleFullscreen": - return void inputManager.trigger("togglefullscreen"); - case "GoHome": - return void inputManager.trigger("home"); - case "GoToSettings": - return void inputManager.trigger("settings"); - case "DisplayContent": + case 'ToggleFullscreen': + inputManager.trigger('togglefullscreen'); + return; + case 'GoHome': + inputManager.trigger('home'); + return; + case 'GoToSettings': + inputManager.trigger('settings'); + return; + case 'DisplayContent': displayContent(cmd, apiClient); break; - case "GoToSearch": - return void inputManager.trigger("search"); - case "DisplayMessage": + case 'GoToSearch': + inputManager.trigger('search'); + return; + case 'DisplayMessage': displayMessage(cmd); break; - case "ToggleOsd": - case "ToggleContextMenu": - case "TakeScreenShot": - case "SendKey": + case 'ToggleOsd': + // todo break; - case "SendString": + case 'ToggleContextMenu': + // todo + break; + case 'TakeScreenShot': + // todo + break; + case 'SendKey': + // todo + break; + case 'SendString': + // todo focusManager.sendText(cmd.Arguments.String); break; default: - console.log("processGeneralCommand does not recognize: " + cmd.Name) + console.log('processGeneralCommand does not recognize: ' + cmd.Name); + break; } - notifyApp() + + notifyApp(); } function onMessageReceived(e, msg) { + var apiClient = this; - if ("Play" === msg.MessageType) { + + if (msg.MessageType === "Play") { + notifyApp(); var serverId = apiClient.serverInfo().Id; - "PlayNext" === msg.Data.PlayCommand ? playbackManager.queueNext({ - ids: msg.Data.ItemIds, - serverId: serverId - }) : "PlayLast" === msg.Data.PlayCommand ? playbackManager.queue({ - ids: msg.Data.ItemIds, - serverId: serverId - }) : playbackManager.play({ - ids: msg.Data.ItemIds, - startPositionTicks: msg.Data.StartPositionTicks, - mediaSourceId: msg.Data.MediaSourceId, - audioStreamIndex: msg.Data.AudioStreamIndex, - subtitleStreamIndex: msg.Data.SubtitleStreamIndex, - startIndex: msg.Data.StartIndex, - serverId: serverId - }) - } else if ("Playstate" === msg.MessageType) "Stop" === msg.Data.Command ? inputManager.trigger("stop") : "Pause" === msg.Data.Command ? inputManager.trigger("pause") : "Unpause" === msg.Data.Command ? inputManager.trigger("play") : "PlayPause" === msg.Data.Command ? inputManager.trigger("playpause") : "Seek" === msg.Data.Command ? playbackManager.seek(msg.Data.SeekPositionTicks) : "NextTrack" === msg.Data.Command ? inputManager.trigger("next") : "PreviousTrack" === msg.Data.Command ? inputManager.trigger("previous") : notifyApp(); - else if ("GeneralCommand" === msg.MessageType) { + + if (msg.Data.PlayCommand === "PlayNext") { + playbackManager.queueNext({ ids: msg.Data.ItemIds, serverId: serverId }); + } + else if (msg.Data.PlayCommand === "PlayLast") { + playbackManager.queue({ ids: msg.Data.ItemIds, serverId: serverId }); + } + else { + playbackManager.play({ + ids: msg.Data.ItemIds, + startPositionTicks: msg.Data.StartPositionTicks, + mediaSourceId: msg.Data.MediaSourceId, + audioStreamIndex: msg.Data.AudioStreamIndex, + subtitleStreamIndex: msg.Data.SubtitleStreamIndex, + startIndex: msg.Data.StartIndex, + serverId: serverId + }); + } + + } + else if (msg.MessageType === "Playstate") { + + if (msg.Data.Command === 'Stop') { + inputManager.trigger('stop'); + } + else if (msg.Data.Command === 'Pause') { + inputManager.trigger('pause'); + } + else if (msg.Data.Command === 'Unpause') { + inputManager.trigger('play'); + } + else if (msg.Data.Command === 'PlayPause') { + inputManager.trigger('playpause'); + } + else if (msg.Data.Command === 'Seek') { + playbackManager.seek(msg.Data.SeekPositionTicks); + } + else if (msg.Data.Command === 'NextTrack') { + inputManager.trigger('next'); + } + else if (msg.Data.Command === 'PreviousTrack') { + inputManager.trigger('previous'); + } else { + notifyApp(); + } + } + else if (msg.MessageType === "GeneralCommand") { var cmd = msg.Data; - processGeneralCommand(cmd, apiClient) - } else if ("UserDataChanged" === msg.MessageType) { - if (msg.Data.UserId === apiClient.getCurrentUserId()) - for (var i = 0, length = msg.Data.UserDataList.length; i < length; i++) events.trigger(serverNotifications, "UserDataChanged", [apiClient, msg.Data.UserDataList[i]]) - } else events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]) + processGeneralCommand(cmd, apiClient); + } + else if (msg.MessageType === "UserDataChanged") { + + if (msg.Data.UserId === apiClient.getCurrentUserId()) { + + for (var i = 0, length = msg.Data.UserDataList.length; i < length; i++) { + events.trigger(serverNotifications, 'UserDataChanged', [apiClient, msg.Data.UserDataList[i]]); + } + } + } + else { + + events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]); + } + } function bindEvents(apiClient) { - events.off(apiClient, "message", onMessageReceived), events.on(apiClient, "message", onMessageReceived) + + events.off(apiClient, "message", onMessageReceived); + events.on(apiClient, "message", onMessageReceived); } - var serverNotifications = {}; - return connectionManager.getApiClients().forEach(bindEvents), events.on(connectionManager, "apiclientcreated", function(e, newApiClient) { - bindEvents(newApiClient) - }), serverNotifications + + connectionManager.getApiClients().forEach(bindEvents); + + events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) { + + bindEvents(newApiClient); + }); + + return serverNotifications; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/input/gamepadtokey.js b/src/bower_components/emby-webcomponents/input/gamepadtokey.js index e02a8fed4e..e8667bef27 100644 --- a/src/bower_components/emby-webcomponents/input/gamepadtokey.js +++ b/src/bower_components/emby-webcomponents/input/gamepadtokey.js @@ -1,153 +1,370 @@ -require(["apphost"], function(appHost) { +// # The MIT License (MIT) +// # +// # Copyright (c) 2016 Microsoft. All rights reserved. +// # +// # Permission is hereby granted, free of charge, to any person obtaining a copy +// # of this software and associated documentation files (the "Software"), to deal +// # in the Software without restriction, including without limitation the rights +// # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// # copies of the Software, and to permit persons to whom the Software is +// # furnished to do so, subject to the following conditions: +// # +// # The above copyright notice and this permission notice shall be included in +// # all copies or substantial portions of the Software. +// # +// # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// # THE SOFTWARE. +require(['apphost'], function (appHost) { "use strict"; + var _GAMEPAD_A_BUTTON_INDEX = 0, + _GAMEPAD_B_BUTTON_INDEX = 1, + _GAMEPAD_DPAD_UP_BUTTON_INDEX = 12, + _GAMEPAD_DPAD_DOWN_BUTTON_INDEX = 13, + _GAMEPAD_DPAD_LEFT_BUTTON_INDEX = 14, + _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX = 15, + _GAMEPAD_A_KEY = "GamepadA", + _GAMEPAD_B_KEY = "GamepadB", + _GAMEPAD_DPAD_UP_KEY = "GamepadDPadUp", + _GAMEPAD_DPAD_DOWN_KEY = "GamepadDPadDown", + _GAMEPAD_DPAD_LEFT_KEY = "GamepadDPadLeft", + _GAMEPAD_DPAD_RIGHT_KEY = "GamepadDPadRight", + _GAMEPAD_LEFT_THUMBSTICK_UP_KEY = "GamepadLeftThumbStickUp", + _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY = "GamepadLeftThumbStickDown", + _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY = "GamepadLeftThumbStickLeft", + _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY = "GamepadLeftThumbStickRight", + _GAMEPAD_A_KEYCODE = 0, + _GAMEPAD_B_KEYCODE = 27, + _GAMEPAD_DPAD_UP_KEYCODE = 38, + _GAMEPAD_DPAD_DOWN_KEYCODE = 40, + _GAMEPAD_DPAD_LEFT_KEYCODE = 37, + _GAMEPAD_DPAD_RIGHT_KEYCODE = 39, + _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE = 38, + _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE = 40, + _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE = 37, + _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE = 39, + _THUMB_STICK_THRESHOLD = 0.75; + + var _leftThumbstickUpPressed = false, + _leftThumbstickDownPressed = false, + _leftThumbstickLeftPressed = false, + _leftThumbstickRightPressed = false, + _dPadUpPressed = false, + _dPadDownPressed = false, + _dPadLeftPressed = false, + _dPadRightPressed = false, + _gamepadAPressed = false, + _gamepadBPressed = false; + + // The set of buttons on the gamepad we listen for. + var ProcessedButtons = [ + _GAMEPAD_DPAD_UP_BUTTON_INDEX, + _GAMEPAD_DPAD_DOWN_BUTTON_INDEX, + _GAMEPAD_DPAD_LEFT_BUTTON_INDEX, + _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX, + _GAMEPAD_A_BUTTON_INDEX, + _GAMEPAD_B_BUTTON_INDEX + ]; + + var _ButtonPressedState = {}; + _ButtonPressedState.getgamepadA = function () { + return _gamepadAPressed; + }; + + _ButtonPressedState.setgamepadA = function (newPressedState) { + raiseKeyEvent(_gamepadAPressed, newPressedState, _GAMEPAD_A_KEY, _GAMEPAD_A_KEYCODE, false, true); + _gamepadAPressed = newPressedState; + }; + + _ButtonPressedState.getgamepadB = function () { + return _gamepadBPressed; + }; + + _ButtonPressedState.setgamepadB = function (newPressedState) { + raiseKeyEvent(_gamepadBPressed, newPressedState, _GAMEPAD_B_KEY, _GAMEPAD_B_KEYCODE); + _gamepadBPressed = newPressedState; + }; + + _ButtonPressedState.getleftThumbstickUp = function () { + return _leftThumbstickUpPressed; + }; + + _ButtonPressedState.setleftThumbstickUp = function (newPressedState) { + raiseKeyEvent(_leftThumbstickUpPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_UP_KEY, _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE, true); + _leftThumbstickUpPressed = newPressedState; + }; + + _ButtonPressedState.getleftThumbstickDown = function () { + return _leftThumbstickDownPressed; + }; + + _ButtonPressedState.setleftThumbstickDown = function (newPressedState) { + raiseKeyEvent(_leftThumbstickDownPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY, _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE, true); + _leftThumbstickDownPressed = newPressedState; + }; + + _ButtonPressedState.getleftThumbstickLeft = function () { + return _leftThumbstickLeftPressed; + }; + + _ButtonPressedState.setleftThumbstickLeft = function (newPressedState) { + raiseKeyEvent(_leftThumbstickLeftPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY, _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE, true); + _leftThumbstickLeftPressed = newPressedState; + }; + + _ButtonPressedState.getleftThumbstickRight = function () { + return _leftThumbstickRightPressed; + }; + + _ButtonPressedState.setleftThumbstickRight = function (newPressedState) { + raiseKeyEvent(_leftThumbstickRightPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY, _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE, true); + _leftThumbstickRightPressed = newPressedState; + }; + + _ButtonPressedState.getdPadUp = function () { + return _dPadUpPressed; + }; + + _ButtonPressedState.setdPadUp = function (newPressedState) { + raiseKeyEvent(_dPadUpPressed, newPressedState, _GAMEPAD_DPAD_UP_KEY, _GAMEPAD_DPAD_UP_KEYCODE, true); + _dPadUpPressed = newPressedState; + }; + + _ButtonPressedState.getdPadDown = function () { + return _dPadDownPressed; + }; + + _ButtonPressedState.setdPadDown = function (newPressedState) { + raiseKeyEvent(_dPadDownPressed, newPressedState, _GAMEPAD_DPAD_DOWN_KEY, _GAMEPAD_DPAD_DOWN_KEYCODE, true); + _dPadDownPressed = newPressedState; + }; + + _ButtonPressedState.getdPadLeft = function () { + return _dPadLeftPressed; + }; + + _ButtonPressedState.setdPadLeft = function (newPressedState) { + raiseKeyEvent(_dPadLeftPressed, newPressedState, _GAMEPAD_DPAD_LEFT_KEY, _GAMEPAD_DPAD_LEFT_KEYCODE, true); + _dPadLeftPressed = newPressedState; + }; + + _ButtonPressedState.getdPadRight = function () { + return _dPadRightPressed; + }; + + _ButtonPressedState.setdPadRight = function (newPressedState) { + raiseKeyEvent(_dPadRightPressed, newPressedState, _GAMEPAD_DPAD_RIGHT_KEY, _GAMEPAD_DPAD_RIGHT_KEYCODE, true); + _dPadRightPressed = newPressedState; + }; + + var times = {}; + function throttle(key) { var time = times[key] || 0; - return (new Date).getTime() - time >= 200 + var now = new Date().getTime(); + + if ((now - time) >= 200) { + //times[key] = now; + return true; + } + + return false; } function resetThrottle(key) { - times[key] = (new Date).getTime() + times[key] = new Date().getTime(); } + var isElectron = navigator.userAgent.toLowerCase().indexOf('electron') !== -1; function allowInput() { - return !(!isElectron && document.hidden) && "Minimized" !== appHost.getWindowState() + + // This would be nice but always seems to return true with electron + if (!isElectron && document.hidden) { + return false; + } + + if (appHost.getWindowState() === 'Minimized') { + return false; + } + + return true; } function raiseEvent(name, key, keyCode) { - if (allowInput()) { - var event = document.createEvent("Event"); - event.initEvent(name, !0, !0), event.key = key, event.keyCode = keyCode, (document.activeElement || document.body).dispatchEvent(event) + + if (!allowInput()) { + return; } + + var event = document.createEvent('Event'); + event.initEvent(name, true, true); + event.key = key; + event.keyCode = keyCode; + (document.activeElement || document.body).dispatchEvent(event); } function clickElement(elem) { - allowInput() && elem.click() + + if (!allowInput()) { + return; + } + + elem.click(); } function raiseKeyEvent(oldPressedState, newPressedState, key, keyCode, enableRepeatKeyDown, clickonKeyUp) { - if (!0 === newPressedState) { - var fire = !1; - !1 === oldPressedState ? (fire = !0, resetThrottle(key)) : enableRepeatKeyDown && (fire = throttle(key)), fire && keyCode && raiseEvent("keydown", key, keyCode) - } else !1 === newPressedState && !0 === oldPressedState && (resetThrottle(key), keyCode && raiseEvent("keyup", key, keyCode), clickonKeyUp && clickElement(document.activeElement || window)) + + // No-op if oldPressedState === newPressedState + if (newPressedState === true) { + + // button down + var fire = false; + + // always fire if this is the initial down press + if (oldPressedState === false) { + fire = true; + resetThrottle(key); + } else if (enableRepeatKeyDown) { + fire = throttle(key); + } + + if (fire && keyCode) { + raiseEvent("keydown", key, keyCode); + } + + } else if (newPressedState === false && oldPressedState === true) { + + resetThrottle(key); + + // button up + if (keyCode) { + raiseEvent("keyup", key, keyCode); + } + if (clickonKeyUp) { + clickElement(document.activeElement || window); + } + } } function runInputLoop() { + // Get the latest gamepad state. var gamepads; - navigator.getGamepads ? gamepads = navigator.getGamepads() : navigator.webkitGetGamepads && (gamepads = navigator.webkitGetGamepads()), gamepads = gamepads || []; + if (navigator.getGamepads) { + gamepads = navigator.getGamepads(); + } else if (navigator.webkitGetGamepads) { + gamepads = navigator.webkitGetGamepads(); + } + gamepads = gamepads || []; var i, j, len; for (i = 0, len = gamepads.length; i < len; i++) { var gamepad = gamepads[i]; if (gamepad) { - var axes = gamepad.axes, - leftStickX = axes[0], - leftStickY = axes[1]; - leftStickX > _THUMB_STICK_THRESHOLD ? _ButtonPressedState.setleftThumbstickRight(!0) : leftStickX < -_THUMB_STICK_THRESHOLD ? _ButtonPressedState.setleftThumbstickLeft(!0) : leftStickY < -_THUMB_STICK_THRESHOLD ? _ButtonPressedState.setleftThumbstickUp(!0) : leftStickY > _THUMB_STICK_THRESHOLD ? _ButtonPressedState.setleftThumbstickDown(!0) : (_ButtonPressedState.setleftThumbstickLeft(!1), _ButtonPressedState.setleftThumbstickRight(!1), _ButtonPressedState.setleftThumbstickUp(!1), _ButtonPressedState.setleftThumbstickDown(!1)); + // Iterate through the axes + var axes = gamepad.axes; + var leftStickX = axes[0]; + var leftStickY = axes[1]; + if (leftStickX > _THUMB_STICK_THRESHOLD) { // Right + _ButtonPressedState.setleftThumbstickRight(true); + } else if (leftStickX < -_THUMB_STICK_THRESHOLD) { // Left + _ButtonPressedState.setleftThumbstickLeft(true); + } else if (leftStickY < -_THUMB_STICK_THRESHOLD) { // Up + _ButtonPressedState.setleftThumbstickUp(true); + } else if (leftStickY > _THUMB_STICK_THRESHOLD) { // Down + _ButtonPressedState.setleftThumbstickDown(true); + } else { + _ButtonPressedState.setleftThumbstickLeft(false); + _ButtonPressedState.setleftThumbstickRight(false); + _ButtonPressedState.setleftThumbstickUp(false); + _ButtonPressedState.setleftThumbstickDown(false); + } + // Iterate through the buttons to see if Left thumbstick, DPad, A and B are pressed. var buttons = gamepad.buttons; - for (j = 0, len = buttons.length; j < len; j++) - if (-1 !== ProcessedButtons.indexOf(j)) - if (buttons[j].pressed) switch (j) { - case _GAMEPAD_DPAD_UP_BUTTON_INDEX: - _ButtonPressedState.setdPadUp(!0); - break; - case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX: - _ButtonPressedState.setdPadDown(!0); - break; - case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX: - _ButtonPressedState.setdPadLeft(!0); - break; - case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX: - _ButtonPressedState.setdPadRight(!0); - break; - case _GAMEPAD_A_BUTTON_INDEX: - _ButtonPressedState.setgamepadA(!0); - break; - case _GAMEPAD_B_BUTTON_INDEX: - _ButtonPressedState.setgamepadB(!0) - } else switch (j) { - case _GAMEPAD_DPAD_UP_BUTTON_INDEX: - _ButtonPressedState.getdPadUp() && _ButtonPressedState.setdPadUp(!1); - break; - case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX: - _ButtonPressedState.getdPadDown() && _ButtonPressedState.setdPadDown(!1); - break; - case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX: - _ButtonPressedState.getdPadLeft() && _ButtonPressedState.setdPadLeft(!1); - break; - case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX: - _ButtonPressedState.getdPadRight() && _ButtonPressedState.setdPadRight(!1); - break; - case _GAMEPAD_A_BUTTON_INDEX: - _ButtonPressedState.getgamepadA() && _ButtonPressedState.setgamepadA(!1); - break; - case _GAMEPAD_B_BUTTON_INDEX: - _ButtonPressedState.getgamepadB() && _ButtonPressedState.setgamepadB(!1) + for (j = 0, len = buttons.length; j < len; j++) { + if (ProcessedButtons.indexOf(j) !== -1) { + + if (buttons[j].pressed) { + switch (j) { + case _GAMEPAD_DPAD_UP_BUTTON_INDEX: + _ButtonPressedState.setdPadUp(true); + break; + case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX: + _ButtonPressedState.setdPadDown(true); + break; + case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX: + _ButtonPressedState.setdPadLeft(true); + break; + case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX: + _ButtonPressedState.setdPadRight(true); + break; + case _GAMEPAD_A_BUTTON_INDEX: + _ButtonPressedState.setgamepadA(true); + break; + case _GAMEPAD_B_BUTTON_INDEX: + _ButtonPressedState.setgamepadB(true); + break; + default: + // No-op + break; + } + } else { + switch (j) { + case _GAMEPAD_DPAD_UP_BUTTON_INDEX: + if (_ButtonPressedState.getdPadUp()) { + _ButtonPressedState.setdPadUp(false); + } + break; + case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX: + if (_ButtonPressedState.getdPadDown()) { + _ButtonPressedState.setdPadDown(false); + } + break; + case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX: + if (_ButtonPressedState.getdPadLeft()) { + _ButtonPressedState.setdPadLeft(false); + } + break; + case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX: + if (_ButtonPressedState.getdPadRight()) { + _ButtonPressedState.setdPadRight(false); + } + break; + case _GAMEPAD_A_BUTTON_INDEX: + if (_ButtonPressedState.getgamepadA()) { + _ButtonPressedState.setgamepadA(false); + } + break; + case _GAMEPAD_B_BUTTON_INDEX: + if (_ButtonPressedState.getgamepadB()) { + _ButtonPressedState.setgamepadB(false); + } + break; + default: + // No-op + break; + } } + } + } } } - requestAnimationFrame(runInputLoop) + // Schedule the next one + requestAnimationFrame(runInputLoop); } - var _GAMEPAD_A_BUTTON_INDEX = 0, - _GAMEPAD_B_BUTTON_INDEX = 1, - _GAMEPAD_DPAD_UP_BUTTON_INDEX = 12, - _GAMEPAD_DPAD_DOWN_BUTTON_INDEX = 13, - _GAMEPAD_DPAD_LEFT_BUTTON_INDEX = 14, - _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX = 15, - _THUMB_STICK_THRESHOLD = .75, - _leftThumbstickUpPressed = !1, - _leftThumbstickDownPressed = !1, - _leftThumbstickLeftPressed = !1, - _leftThumbstickRightPressed = !1, - _dPadUpPressed = !1, - _dPadDownPressed = !1, - _dPadLeftPressed = !1, - _dPadRightPressed = !1, - _gamepadAPressed = !1, - _gamepadBPressed = !1, - ProcessedButtons = [_GAMEPAD_DPAD_UP_BUTTON_INDEX, _GAMEPAD_DPAD_DOWN_BUTTON_INDEX, _GAMEPAD_DPAD_LEFT_BUTTON_INDEX, _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX, _GAMEPAD_A_BUTTON_INDEX, _GAMEPAD_B_BUTTON_INDEX], - _ButtonPressedState = {}; - _ButtonPressedState.getgamepadA = function() { - return _gamepadAPressed - }, _ButtonPressedState.setgamepadA = function(newPressedState) { - raiseKeyEvent(_gamepadAPressed, newPressedState, "GamepadA", 0, !1, !0), _gamepadAPressed = newPressedState - }, _ButtonPressedState.getgamepadB = function() { - return _gamepadBPressed - }, _ButtonPressedState.setgamepadB = function(newPressedState) { - raiseKeyEvent(_gamepadBPressed, newPressedState, "GamepadB", 27), _gamepadBPressed = newPressedState - }, _ButtonPressedState.getleftThumbstickUp = function() { - return _leftThumbstickUpPressed - }, _ButtonPressedState.setleftThumbstickUp = function(newPressedState) { - raiseKeyEvent(_leftThumbstickUpPressed, newPressedState, "GamepadLeftThumbStickUp", 38, !0), _leftThumbstickUpPressed = newPressedState - }, _ButtonPressedState.getleftThumbstickDown = function() { - return _leftThumbstickDownPressed - }, _ButtonPressedState.setleftThumbstickDown = function(newPressedState) { - raiseKeyEvent(_leftThumbstickDownPressed, newPressedState, "GamepadLeftThumbStickDown", 40, !0), _leftThumbstickDownPressed = newPressedState - }, _ButtonPressedState.getleftThumbstickLeft = function() { - return _leftThumbstickLeftPressed - }, _ButtonPressedState.setleftThumbstickLeft = function(newPressedState) { - raiseKeyEvent(_leftThumbstickLeftPressed, newPressedState, "GamepadLeftThumbStickLeft", 37, !0), _leftThumbstickLeftPressed = newPressedState - }, _ButtonPressedState.getleftThumbstickRight = function() { - return _leftThumbstickRightPressed - }, _ButtonPressedState.setleftThumbstickRight = function(newPressedState) { - raiseKeyEvent(_leftThumbstickRightPressed, newPressedState, "GamepadLeftThumbStickRight", 39, !0), _leftThumbstickRightPressed = newPressedState - }, _ButtonPressedState.getdPadUp = function() { - return _dPadUpPressed - }, _ButtonPressedState.setdPadUp = function(newPressedState) { - raiseKeyEvent(_dPadUpPressed, newPressedState, "GamepadDPadUp", 38, !0), _dPadUpPressed = newPressedState - }, _ButtonPressedState.getdPadDown = function() { - return _dPadDownPressed - }, _ButtonPressedState.setdPadDown = function(newPressedState) { - raiseKeyEvent(_dPadDownPressed, newPressedState, "GamepadDPadDown", 40, !0), _dPadDownPressed = newPressedState - }, _ButtonPressedState.getdPadLeft = function() { - return _dPadLeftPressed - }, _ButtonPressedState.setdPadLeft = function(newPressedState) { - raiseKeyEvent(_dPadLeftPressed, newPressedState, "GamepadDPadLeft", 37, !0), _dPadLeftPressed = newPressedState - }, _ButtonPressedState.getdPadRight = function() { - return _dPadRightPressed - }, _ButtonPressedState.setdPadRight = function(newPressedState) { - raiseKeyEvent(_dPadRightPressed, newPressedState, "GamepadDPadRight", 39, !0), _dPadRightPressed = newPressedState - }; - var times = {}, - isElectron = -1 !== navigator.userAgent.toLowerCase().indexOf("electron"); - runInputLoop(), window.navigator && "string" == typeof window.navigator.gamepadInputEmulation && (window.navigator.gamepadInputEmulation = "gamepad") + + runInputLoop(); + + // The gamepadInputEmulation is a string property that exists in JavaScript UWAs and in WebViews in UWAs. + // It won't exist in Win8.1 style apps or browsers. + if (window.navigator && typeof window.navigator.gamepadInputEmulation === "string") { + // We want the gamepad to provide gamepad VK keyboard events rather than moving a + // mouse like cursor. Set to "keyboard", the gamepad will provide such keyboard events + // and provide input to the DOM navigator.getGamepads API. + window.navigator.gamepadInputEmulation = "gamepad"; + } + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/input/mouse.js b/src/bower_components/emby-webcomponents/input/mouse.js index 56984561b0..16a9050530 100644 --- a/src/bower_components/emby-webcomponents/input/mouse.js +++ b/src/bower_components/emby-webcomponents/input/mouse.js @@ -1,75 +1,169 @@ -define(["inputManager", "focusManager", "browser", "layoutManager", "events", "dom"], function(inputmanager, focusManager, browser, layoutManager, events, dom) { - "use strict"; +define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'dom'], function (inputmanager, focusManager, browser, layoutManager, events, dom) { + 'use strict'; + + var self = {}; + + var lastMouseInputTime = new Date().getTime(); + var isMouseIdle; function mouseIdleTime() { - return (new Date).getTime() - lastMouseInputTime + return new Date().getTime() - lastMouseInputTime; } function notifyApp() { - inputmanager.notifyMouseMove() + + inputmanager.notifyMouseMove(); } function removeIdleClasses() { + var classList = document.body.classList; - classList.remove("mouseIdle"), classList.remove("mouseIdle-tv") + + classList.remove('mouseIdle'); + classList.remove('mouseIdle-tv'); } function addIdleClasses() { + var classList = document.body.classList; - classList.add("mouseIdle"), layoutManager.tv && classList.add("mouseIdle-tv") + + classList.add('mouseIdle'); + + if (layoutManager.tv) { + classList.add('mouseIdle-tv'); + } } + var lastPointerMoveData; function onPointerMove(e) { - var eventX = e.screenX, - eventY = e.screenY; - if (void 0 !== eventX || void 0 !== eventY) { - var obj = lastPointerMoveData; - if (!obj) return void(lastPointerMoveData = { + + var eventX = e.screenX; + var eventY = e.screenY; + + // if coord don't exist how could it move + if (typeof eventX === "undefined" && typeof eventY === "undefined") { + return; + } + + var obj = lastPointerMoveData; + if (!obj) { + lastPointerMoveData = { x: eventX, y: eventY - }); - Math.abs(eventX - obj.x) < 10 && Math.abs(eventY - obj.y) < 10 || (obj.x = eventX, obj.y = eventY, lastMouseInputTime = (new Date).getTime(), notifyApp(), isMouseIdle && (isMouseIdle = !1, removeIdleClasses(), events.trigger(self, "mouseactive"))) + }; + return; + } + + // if coord are same, it didn't move + if (Math.abs(eventX - obj.x) < 10 && Math.abs(eventY - obj.y) < 10) { + return; + } + + obj.x = eventX; + obj.y = eventY; + + lastMouseInputTime = new Date().getTime(); + notifyApp(); + + if (isMouseIdle) { + isMouseIdle = false; + removeIdleClasses(); + events.trigger(self, 'mouseactive'); } } function onPointerEnter(e) { - if ("mouse" === (e.pointerType || (layoutManager.mobile ? "touch" : "mouse")) && !isMouseIdle) { - var parent = focusManager.focusableParent(e.target); - parent && focusManager.focus(parent) + + var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse'); + + if (pointerType === 'mouse') { + if (!isMouseIdle) { + var parent = focusManager.focusableParent(e.target); + if (parent) { + focusManager.focus(parent); + } + } } } function enableFocusWithMouse() { - return !!layoutManager.tv && (!browser.web0s && !!browser.tv) + + if (!layoutManager.tv) { + return false; + } + + if (browser.web0s) { + return false; + } + + if (browser.tv) { + return true; + } + + return false; } function onMouseInterval() { - !isMouseIdle && mouseIdleTime() >= 5e3 && (isMouseIdle = !0, addIdleClasses(), events.trigger(self, "mouseidle")) + + if (!isMouseIdle && mouseIdleTime() >= 5000) { + isMouseIdle = true; + addIdleClasses(); + events.trigger(self, 'mouseidle'); + } } + var mouseInterval; function startMouseInterval() { - mouseInterval || (mouseInterval = setInterval(onMouseInterval, 5e3)) + + if (!mouseInterval) { + mouseInterval = setInterval(onMouseInterval, 5000); + } } function stopMouseInterval() { + var interval = mouseInterval; - interval && (clearInterval(interval), mouseInterval = null), removeIdleClasses() + + if (interval) { + clearInterval(interval); + mouseInterval = null; + } + + removeIdleClasses(); } function initMouse() { - stopMouseInterval(), dom.removeEventListener(document, window.PointerEvent ? "pointermove" : "mousemove", onPointerMove, { - passive: !0 - }), layoutManager.mobile || (startMouseInterval(), dom.addEventListener(document, window.PointerEvent ? "pointermove" : "mousemove", onPointerMove, { - passive: !0 - })), dom.removeEventListener(document, window.PointerEvent ? "pointerenter" : "mouseenter", onPointerEnter, { - capture: !0, - passive: !0 - }), enableFocusWithMouse() && dom.addEventListener(document, window.PointerEvent ? "pointerenter" : "mouseenter", onPointerEnter, { - capture: !0, - passive: !0 - }) + + stopMouseInterval(); + + dom.removeEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, { + passive: true + }); + + if (!layoutManager.mobile) { + startMouseInterval(); + + dom.addEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, { + passive: true + }); + } + + dom.removeEventListener(document, (window.PointerEvent ? 'pointerenter' : 'mouseenter'), onPointerEnter, { + capture: true, + passive: true + }); + + if (enableFocusWithMouse()) { + dom.addEventListener(document, (window.PointerEvent ? 'pointerenter' : 'mouseenter'), onPointerEnter, { + capture: true, + passive: true + }); + } } - var isMouseIdle, lastPointerMoveData, mouseInterval, self = {}, - lastMouseInputTime = (new Date).getTime(); - return initMouse(), events.on(layoutManager, "modechange", initMouse), self + + initMouse(); + + events.on(layoutManager, 'modechange', initMouse); + + return self; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/inputmanager.js b/src/bower_components/emby-webcomponents/inputmanager.js index 2977f284e3..f79eaa58da 100644 --- a/src/bower_components/emby-webcomponents/inputmanager.js +++ b/src/bower_components/emby-webcomponents/inputmanager.js @@ -1,211 +1,285 @@ -define(["playbackManager", "focusManager", "appRouter", "dom"], function(playbackManager, focusManager, appRouter, dom) { - "use strict"; +define(['playbackManager', 'focusManager', 'appRouter', 'dom'], function (playbackManager, focusManager, appRouter, dom) { + 'use strict'; + + var lastInputTime = new Date().getTime(); function notify() { - lastInputTime = (new Date).getTime(), handleCommand("unknown") + lastInputTime = new Date().getTime(); + + handleCommand('unknown'); } function notifyMouseMove() { - lastInputTime = (new Date).getTime() + lastInputTime = new Date().getTime(); } function idleTime() { - return (new Date).getTime() - lastInputTime + return new Date().getTime() - lastInputTime; } function select(sourceElement) { - sourceElement.click() + + sourceElement.click(); } + var eventListenerCount = 0; function on(scope, fn) { - eventListenerCount++, dom.addEventListener(scope, "command", fn, {}) + eventListenerCount++; + dom.addEventListener(scope, 'command', fn, { + + }); } function off(scope, fn) { - eventListenerCount && eventListenerCount--, dom.removeEventListener(scope, "command", fn, {}) + + if (eventListenerCount) { + eventListenerCount--; + } + + dom.removeEventListener(scope, 'command', fn, { + + }); } + var commandTimes = {}; + function checkCommandTime(command) { - var last = commandTimes[command] || 0, - now = (new Date).getTime(); - return !(now - last < 1e3) && (commandTimes[command] = now, !0) + + var last = commandTimes[command] || 0; + var now = new Date().getTime(); + + if ((now - last) < 1000) { + return false; + } + + commandTimes[command] = now; + return true; } function handleCommand(name, options) { - lastInputTime = (new Date).getTime(); - var sourceElement = options ? options.sourceElement : null; - if (sourceElement && (sourceElement = focusManager.focusableParent(sourceElement)), sourceElement = sourceElement || document.activeElement || window, eventListenerCount) { + + lastInputTime = new Date().getTime(); + + var sourceElement = (options ? options.sourceElement : null); + + if (sourceElement) { + sourceElement = focusManager.focusableParent(sourceElement); + } + + sourceElement = sourceElement || document.activeElement || window; + + if (eventListenerCount) { var customEvent = new CustomEvent("command", { detail: { command: name }, - bubbles: !0, - cancelable: !0 + bubbles: true, + cancelable: true }); - if (!sourceElement.dispatchEvent(customEvent)) return + + var eventResult = sourceElement.dispatchEvent(customEvent); + if (!eventResult) { + // event cancelled + return; + } } + switch (name) { - case "up": + + case 'up': focusManager.moveUp(sourceElement); break; - case "down": + case 'down': focusManager.moveDown(sourceElement); break; - case "left": + case 'left': focusManager.moveLeft(sourceElement); break; - case "right": + case 'right': focusManager.moveRight(sourceElement); break; - case "home": + case 'home': appRouter.goHome(); break; - case "settings": + case 'settings': appRouter.showSettings(); break; - case "back": + case 'back': appRouter.back(); break; - case "forward": + case 'forward': break; - case "select": + case 'select': select(sourceElement); break; - case "pageup": - case "pagedown": - case "end": + case 'pageup': break; - case "menu": - case "info": + case 'pagedown': break; - case "nextchapter": + case 'end': + break; + case 'menu': + case 'info': + break; + case 'nextchapter': playbackManager.nextChapter(); break; - case "next": - case "nexttrack": + case 'next': + case 'nexttrack': playbackManager.nextTrack(); break; - case "previous": - case "previoustrack": + case 'previous': + case 'previoustrack': playbackManager.previousTrack(); break; - case "previouschapter": + case 'previouschapter': playbackManager.previousChapter(); break; - case "guide": + case 'guide': appRouter.showGuide(); break; - case "recordedtv": + case 'recordedtv': appRouter.showRecordedTV(); break; - case "record": + case 'record': break; - case "livetv": + case 'livetv': appRouter.showLiveTV(); break; - case "mute": - playbackManager.setMute(!0); + case 'mute': + playbackManager.setMute(true); break; - case "unmute": - playbackManager.setMute(!1); + case 'unmute': + playbackManager.setMute(false); break; - case "togglemute": + case 'togglemute': playbackManager.toggleMute(); break; - case "channelup": + case 'channelup': playbackManager.channelUp(); break; - case "channeldown": + case 'channeldown': playbackManager.channelDown(); break; - case "volumedown": + case 'volumedown': playbackManager.volumeDown(); break; - case "volumeup": + case 'volumeup': playbackManager.volumeUp(); break; - case "play": + case 'play': playbackManager.unpause(); break; - case "pause": + case 'pause': playbackManager.pause(); break; - case "playpause": + case 'playpause': playbackManager.playPause(); break; - case "stop": - checkCommandTime("stop") && playbackManager.stop(); + case 'stop': + if (checkCommandTime('stop')) { + playbackManager.stop(); + } break; - case "changezoom": + case 'changezoom': playbackManager.toggleAspectRatio(); break; - case "changeaudiotrack": + case 'changeaudiotrack': playbackManager.changeAudioStream(); break; - case "changesubtitletrack": + case 'changesubtitletrack': playbackManager.changeSubtitleStream(); break; - case "search": + case 'search': appRouter.showSearch(); break; - case "favorites": + case 'favorites': appRouter.showFavorites(); break; - case "fastforward": + case 'fastforward': playbackManager.fastForward(); break; - case "rewind": + case 'rewind': playbackManager.rewind(); break; - case "togglefullscreen": + case 'togglefullscreen': playbackManager.toggleFullscreen(); break; - case "disabledisplaymirror": - playbackManager.enableDisplayMirroring(!1); + case 'disabledisplaymirror': + playbackManager.enableDisplayMirroring(false); break; - case "enabledisplaymirror": - playbackManager.enableDisplayMirroring(!0); + case 'enabledisplaymirror': + playbackManager.enableDisplayMirroring(true); break; - case "toggledisplaymirror": + case 'toggledisplaymirror': playbackManager.toggleDisplayMirroring(); break; - case "togglestats": + case 'togglestats': + //playbackManager.toggleStats(); break; - case "movies": - case "music": - case "tv": + case 'movies': + // TODO appRouter.goHome(); break; - case "nowplaying": + case 'music': + // TODO + appRouter.goHome(); + break; + case 'tv': + // TODO + appRouter.goHome(); + break; + case 'nowplaying': appRouter.showNowPlaying(); break; - case "save": - case "screensaver": - case "refresh": - case "changebrightness": - case "red": - case "green": - case "yellow": - case "blue": - case "grey": - case "brown": + case 'save': break; - case "repeatnone": - playbackManager.setRepeatMode("RepeatNone"); + case 'screensaver': + // TODO break; - case "repeatall": - playbackManager.setRepeatMode("RepeatAll"); + case 'refresh': + // TODO + break; + case 'changebrightness': + // TODO + break; + case 'red': + // TODO + break; + case 'green': + // TODO + break; + case 'yellow': + // TODO + break; + case 'blue': + // TODO + break; + case 'grey': + // TODO + break; + case 'brown': + // TODO + break; + case 'repeatnone': + playbackManager.setRepeatMode('RepeatNone'); + break; + case 'repeatall': + playbackManager.setRepeatMode('RepeatAll'); + break; + case 'repeatone': + playbackManager.setRepeatMode('RepeatOne'); + break; + default: break; - case "repeatone": - playbackManager.setRepeatMode("RepeatOne") } } - var lastInputTime = (new Date).getTime(), - eventListenerCount = 0, - commandTimes = {}; - return dom.addEventListener(document, "click", notify, { - passive: !0 - }), { + + dom.addEventListener(document, 'click', notify, { + passive: true + }); + + return { trigger: handleCommand, handle: handleCommand, notify: notify, @@ -213,5 +287,5 @@ define(["playbackManager", "focusManager", "appRouter", "dom"], function(playbac idleTime: idleTime, on: on, off: off - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/itemcontextmenu.js b/src/bower_components/emby-webcomponents/itemcontextmenu.js index ee61308267..47451751eb 100644 --- a/src/bower_components/emby-webcomponents/itemcontextmenu.js +++ b/src/bower_components/emby-webcomponents/itemcontextmenu.js @@ -1,359 +1,674 @@ -define(["apphost", "globalize", "connectionManager", "itemHelper", "appRouter", "playbackManager", "loading", "appSettings", "browser", "actionsheet"], function(appHost, globalize, connectionManager, itemHelper, appRouter, playbackManager, loading, appSettings, browser, actionsheet) { - "use strict"; +define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', 'playbackManager', 'loading', 'appSettings', 'browser', 'actionsheet'], function (appHost, globalize, connectionManager, itemHelper, appRouter, playbackManager, loading, appSettings, browser, actionsheet) { + 'use strict'; function getCommands(options) { - var item = options.item, - canPlay = playbackManager.canPlay(item), - commands = [], - user = options.user, - restrictOptions = (browser.operaTv || browser.web0s) && !user.Policy.IsAdministrator; - canPlay && "Photo" !== item.MediaType && (!1 !== options.play && commands.push({ - name: globalize.translate("sharedcomponents#Play"), - id: "resume" - }), options.playAllFromHere && "Program" !== item.Type && "TvChannel" !== item.Type && commands.push({ - name: globalize.translate("sharedcomponents#PlayAllFromHere"), - id: "playallfromhere" - })), playbackManager.canQueue(item) && (!1 !== options.queue && commands.push({ - name: globalize.translate("sharedcomponents#AddToPlayQueue"), - id: "queue" - }), !1 !== options.queue && commands.push({ - name: globalize.translate("sharedcomponents#PlayNext"), - id: "queuenext" - })), (item.IsFolder || "MusicArtist" === item.Type || "MusicGenre" === item.Type) && "livetv" !== item.CollectionType && !1 !== options.shuffle && commands.push({ - name: globalize.translate("sharedcomponents#Shuffle"), - id: "shuffle" - }), "Audio" !== item.MediaType && "MusicAlbum" !== item.Type && "MusicArtist" !== item.Type && "MusicGenre" !== item.Type || !1 === options.instantMix || itemHelper.isLocalItem(item) || commands.push({ - name: globalize.translate("sharedcomponents#InstantMix"), - id: "instantmix" - }), commands.length && commands.push({ - divider: !0 - }), restrictOptions || (itemHelper.supportsAddingToCollection(item) && commands.push({ - name: globalize.translate("sharedcomponents#AddToCollection"), - id: "addtocollection" - }), itemHelper.supportsAddingToPlaylist(item) && commands.push({ - name: globalize.translate("sharedcomponents#AddToPlaylist"), - id: "addtoplaylist" - })), "Timer" === item.Type && user.Policy.EnableLiveTvManagement && !1 !== options.cancelTimer && commands.push({ - name: globalize.translate("sharedcomponents#CancelRecording"), - id: "canceltimer" - }), "Recording" === item.Type && "InProgress" === item.Status && user.Policy.EnableLiveTvManagement && !1 !== options.cancelTimer && commands.push({ - name: globalize.translate("sharedcomponents#CancelRecording"), - id: "canceltimer" - }), "SeriesTimer" === item.Type && user.Policy.EnableLiveTvManagement && !1 !== options.cancelTimer && commands.push({ - name: globalize.translate("sharedcomponents#CancelSeries"), - id: "cancelseriestimer" - }), itemHelper.canConvert(item, user, connectionManager.getApiClient(item)) && commands.push({ - name: globalize.translate("sharedcomponents#Convert"), - id: "convert" - }), item.CanDelete && !1 !== options.deleteItem && ("Playlist" === item.Type || "BoxSet" === item.Type ? commands.push({ - name: globalize.translate("sharedcomponents#Delete"), - id: "delete" - }) : commands.push({ - name: globalize.translate("sharedcomponents#DeleteMedia"), - id: "delete" - })), item.CanDownload && appHost.supports("filedownload") && commands.push({ - name: globalize.translate("sharedcomponents#Download"), - id: "download" - }), appHost.supports("sync") && !1 !== options.syncLocal && itemHelper.canSync(user, item) && commands.push({ - name: globalize.translate("sharedcomponents#Download"), - id: "synclocal" - }); - var canEdit = itemHelper.canEdit(user, item); - if (canEdit && !1 !== options.edit && "SeriesTimer" !== item.Type) { - var text = "Timer" === item.Type || "SeriesTimer" === item.Type ? globalize.translate("sharedcomponents#Edit") : globalize.translate("sharedcomponents#EditMetadata"); - commands.push({ - name: text, - id: "edit" - }) + + var item = options.item; + + var canPlay = playbackManager.canPlay(item); + + var commands = []; + + var user = options.user; + + var restrictOptions = (browser.operaTv || browser.web0s) && !user.Policy.IsAdministrator; + + if (canPlay && item.MediaType !== 'Photo') { + if (options.play !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#Play'), + id: 'resume' + }); + } + + if (options.playAllFromHere && item.Type !== 'Program' && item.Type !== 'TvChannel') { + commands.push({ + name: globalize.translate('sharedcomponents#PlayAllFromHere'), + id: 'playallfromhere' + }); + } } - return itemHelper.canEditImages(user, item) && !1 !== options.editImages && commands.push({ - name: globalize.translate("sharedcomponents#EditImages"), - id: "editimages" - }), canEdit && ("Video" !== item.MediaType || "TvChannel" === item.Type || "Program" === item.Type || "Virtual" === item.LocationType || "Recording" === item.Type && "Completed" !== item.Status || !1 !== options.editSubtitles && commands.push({ - name: globalize.translate("sharedcomponents#EditSubtitles"), - id: "editsubtitles" - })), !1 !== options.identify && itemHelper.canIdentify(user, item) && commands.push({ - name: globalize.translate("sharedcomponents#Identify"), - id: "identify" - }), "Program" === item.Type && !1 !== options.record && item.TimerId && commands.push({ - name: Globalize.translate("sharedcomponents#ManageRecording"), - id: "record" - }), "Program" === item.Type && !1 !== options.record && (item.TimerId || commands.push({ - name: Globalize.translate("sharedcomponents#Record"), - id: "record" - })), itemHelper.canRefreshMetadata(item, user) && commands.push({ - name: globalize.translate("sharedcomponents#RefreshMetadata"), - id: "refresh" - }), item.PlaylistItemId && options.playlistId && commands.push({ - name: globalize.translate("sharedcomponents#RemoveFromPlaylist"), - id: "removefromplaylist" - }), options.collectionId && commands.push({ - name: globalize.translate("sharedcomponents#RemoveFromCollection"), - id: "removefromcollection" - }), restrictOptions || !0 === options.share && itemHelper.canShare(item, user) && commands.push({ - name: globalize.translate("sharedcomponents#Share"), - id: "share" - }), !1 !== options.sync && itemHelper.canSync(user, item) && commands.push({ - name: globalize.translate("sharedcomponents#Sync"), - id: "sync" - }), !1 !== options.openAlbum && item.AlbumId && "Photo" !== item.MediaType && commands.push({ - name: Globalize.translate("sharedcomponents#ViewAlbum"), - id: "album" - }), !1 !== options.openArtist && item.ArtistItems && item.ArtistItems.length && commands.push({ - name: Globalize.translate("sharedcomponents#ViewArtist"), - id: "artist" - }), commands + + if (playbackManager.canQueue(item)) { + + if (options.queue !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#AddToPlayQueue'), + id: 'queue' + }); + } + + if (options.queue !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#PlayNext'), + id: 'queuenext' + }); + } + + //if (options.queueAllFromHere) { + // commands.push({ + // name: globalize.translate('sharedcomponents#QueueAllFromHere'), + // id: 'queueallfromhere' + // }); + //} + } + + + + if (item.IsFolder || item.Type === "MusicArtist" || item.Type === "MusicGenre") { + if (item.CollectionType !== 'livetv') { + if (options.shuffle !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#Shuffle'), + id: 'shuffle' + }); + } + } + } + + if (item.MediaType === "Audio" || item.Type === "MusicAlbum" || item.Type === "MusicArtist" || item.Type === "MusicGenre") { + if (options.instantMix !== false && !itemHelper.isLocalItem(item)) { + commands.push({ + name: globalize.translate('sharedcomponents#InstantMix'), + id: 'instantmix' + }); + } + } + + if (commands.length) { + commands.push({ + divider: true + }); + } + + if (!restrictOptions) { + if (itemHelper.supportsAddingToCollection(item)) { + commands.push({ + name: globalize.translate('sharedcomponents#AddToCollection'), + id: 'addtocollection' + }); + } + + if (itemHelper.supportsAddingToPlaylist(item)) { + commands.push({ + name: globalize.translate('sharedcomponents#AddToPlaylist'), + id: 'addtoplaylist' + }); + } + } + + if ((item.Type === 'Timer') && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#CancelRecording'), + id: 'canceltimer' + }); + } + + if ((item.Type === 'Recording' && item.Status === 'InProgress') && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#CancelRecording'), + id: 'canceltimer' + }); + } + + if ((item.Type === 'SeriesTimer') && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#CancelSeries'), + id: 'cancelseriestimer' + }); + } + + if (itemHelper.canConvert(item, user, connectionManager.getApiClient(item))) { + commands.push({ + name: globalize.translate('sharedcomponents#Convert'), + id: 'convert' + }); + } + + if (item.CanDelete && options.deleteItem !== false) { + + if (item.Type === 'Playlist' || item.Type === 'BoxSet') { + commands.push({ + name: globalize.translate('sharedcomponents#Delete'), + id: 'delete' + }); + } else { + commands.push({ + name: globalize.translate('sharedcomponents#DeleteMedia'), + id: 'delete' + }); + } + } + + if (item.CanDownload && appHost.supports('filedownload')) { + commands.push({ + name: globalize.translate('sharedcomponents#Download'), + id: 'download' + }); + } + + if (appHost.supports('sync') && options.syncLocal !== false) { + if (itemHelper.canSync(user, item)) { + commands.push({ + name: globalize.translate('sharedcomponents#Download'), + id: 'synclocal' + }); + } + } + + var canEdit = itemHelper.canEdit(user, item); + if (canEdit) { + + if (options.edit !== false && item.Type !== 'SeriesTimer') { + + var text = (item.Type === 'Timer' || item.Type === 'SeriesTimer') ? globalize.translate('sharedcomponents#Edit') : globalize.translate('sharedcomponents#EditMetadata'); + + commands.push({ + name: text, + id: 'edit' + }); + } + } + + if (itemHelper.canEditImages(user, item)) { + + if (options.editImages !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#EditImages'), + id: 'editimages' + }); + } + } + + if (canEdit) { + + if (item.MediaType === 'Video' && item.Type !== 'TvChannel' && item.Type !== 'Program' && item.LocationType !== 'Virtual' && !(item.Type === 'Recording' && item.Status !== 'Completed')) { + if (options.editSubtitles !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#EditSubtitles'), + id: 'editsubtitles' + }); + } + } + } + + if (options.identify !== false) { + if (itemHelper.canIdentify(user, item)) { + commands.push({ + name: globalize.translate('sharedcomponents#Identify'), + id: 'identify' + }); + } + } + + if (item.Type === 'Program' && options.record !== false) { + + if (item.TimerId) { + commands.push({ + name: Globalize.translate('sharedcomponents#ManageRecording'), + id: 'record' + }); + } + } + + if (item.Type === 'Program' && options.record !== false) { + + if (!item.TimerId) { + commands.push({ + name: Globalize.translate('sharedcomponents#Record'), + id: 'record' + }); + } + } + + if (itemHelper.canRefreshMetadata(item, user)) { + commands.push({ + name: globalize.translate('sharedcomponents#RefreshMetadata'), + id: 'refresh' + }); + } + + if (item.PlaylistItemId && options.playlistId) { + commands.push({ + name: globalize.translate('sharedcomponents#RemoveFromPlaylist'), + id: 'removefromplaylist' + }); + } + + if (options.collectionId) { + commands.push({ + name: globalize.translate('sharedcomponents#RemoveFromCollection'), + id: 'removefromcollection' + }); + } + + if (!restrictOptions) { + if (options.share === true) { + if (itemHelper.canShare(item, user)) { + commands.push({ + name: globalize.translate('sharedcomponents#Share'), + id: 'share' + }); + } + } + } + + if (options.sync !== false) { + if (itemHelper.canSync(user, item)) { + commands.push({ + name: globalize.translate('sharedcomponents#Sync'), + id: 'sync' + }); + } + } + + if (options.openAlbum !== false && item.AlbumId && item.MediaType !== 'Photo') { + commands.push({ + name: Globalize.translate('sharedcomponents#ViewAlbum'), + id: 'album' + }); + } + + if (options.openArtist !== false && item.ArtistItems && item.ArtistItems.length) { + commands.push({ + name: Globalize.translate('sharedcomponents#ViewArtist'), + id: 'artist' + }); + } + + return commands; } function getResolveFunction(resolve, id, changed, deleted) { - return function() { + + return function () { resolve({ command: id, updated: changed, deleted: deleted - }) - } + }); + }; } function executeCommand(item, id, options) { - var itemId = item.Id, - serverId = item.ServerId, - apiClient = connectionManager.getApiClient(serverId); - return new Promise(function(resolve, reject) { + + var itemId = item.Id; + var serverId = item.ServerId; + var apiClient = connectionManager.getApiClient(serverId); + + return new Promise(function (resolve, reject) { + switch (id) { - case "addtocollection": - require(["collectionEditor"], function(collectionEditor) { - (new collectionEditor).show({ - items: [itemId], - serverId: serverId - }).then(getResolveFunction(resolve, id, !0), getResolveFunction(resolve, id)) + + case 'addtocollection': + { + require(['collectionEditor'], function (collectionEditor) { + + new collectionEditor().show({ + items: [itemId], + serverId: serverId + + }).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); + }); + break; + } + case 'addtoplaylist': + { + require(['playlistEditor'], function (playlistEditor) { + + new playlistEditor().show({ + items: [itemId], + serverId: serverId + + }).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); + }); + break; + } + case 'download': + { + require(['fileDownloader'], function (fileDownloader) { + var downloadHref = apiClient.getItemDownloadUrl(itemId); + + fileDownloader.download([ + { + url: downloadHref, + itemId: itemId, + serverId: serverId + }]); + + getResolveFunction(getResolveFunction(resolve, id), id)(); + }); + + break; + } + case 'editsubtitles': + { + require(['subtitleEditor'], function (subtitleEditor) { + + subtitleEditor.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); + }); + break; + } + case 'edit': + { + editItem(apiClient, item).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); + break; + } + case 'editimages': + { + require(['imageEditor'], function (imageEditor) { + + imageEditor.show({ + itemId: itemId, + serverId: serverId + + }).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); + }); + break; + } + case 'identify': + { + require(['itemIdentifier'], function (itemIdentifier) { + + itemIdentifier.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); + }); + break; + } + case 'refresh': + { + refresh(apiClient, item); + getResolveFunction(resolve, id)(); + break; + } + case 'open': + { + appRouter.showItem(item); + getResolveFunction(resolve, id)(); + break; + } + case 'play': + { + play(item, false); + getResolveFunction(resolve, id)(); + break; + } + case 'resume': + { + play(item, true); + getResolveFunction(resolve, id)(); + break; + } + case 'queue': + { + play(item, false, true); + getResolveFunction(resolve, id)(); + break; + } + case 'queuenext': + { + play(item, false, true, true); + getResolveFunction(resolve, id)(); + break; + } + case 'record': + require(['recordingCreator'], function (recordingCreator) { + recordingCreator.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); }); break; - case "addtoplaylist": - require(["playlistEditor"], function(playlistEditor) { - (new playlistEditor).show({ - items: [itemId], - serverId: serverId - }).then(getResolveFunction(resolve, id, !0), getResolveFunction(resolve, id)) - }); - break; - case "download": - require(["fileDownloader"], function(fileDownloader) { - var downloadHref = apiClient.getItemDownloadUrl(itemId); - fileDownloader.download([{ - url: downloadHref, - itemId: itemId, - serverId: serverId - }]), getResolveFunction(getResolveFunction(resolve, id), id)() - }); - break; - case "editsubtitles": - require(["subtitleEditor"], function(subtitleEditor) { - subtitleEditor.show(itemId, serverId).then(getResolveFunction(resolve, id, !0), getResolveFunction(resolve, id)) - }); - break; - case "edit": - editItem(apiClient, item).then(getResolveFunction(resolve, id, !0), getResolveFunction(resolve, id)); - break; - case "editimages": - require(["imageEditor"], function(imageEditor) { - imageEditor.show({ - itemId: itemId, - serverId: serverId - }).then(getResolveFunction(resolve, id, !0), getResolveFunction(resolve, id)) - }); - break; - case "identify": - require(["itemIdentifier"], function(itemIdentifier) { - itemIdentifier.show(itemId, serverId).then(getResolveFunction(resolve, id, !0), getResolveFunction(resolve, id)) - }); - break; - case "refresh": - refresh(apiClient, item), getResolveFunction(resolve, id)(); - break; - case "open": - appRouter.showItem(item), getResolveFunction(resolve, id)(); - break; - case "play": - play(item, !1), getResolveFunction(resolve, id)(); - break; - case "resume": - play(item, !0), getResolveFunction(resolve, id)(); - break; - case "queue": - play(item, !1, !0), getResolveFunction(resolve, id)(); - break; - case "queuenext": - play(item, !1, !0, !0), getResolveFunction(resolve, id)(); - break; - case "record": - require(["recordingCreator"], function(recordingCreator) { - recordingCreator.show(itemId, serverId).then(getResolveFunction(resolve, id, !0), getResolveFunction(resolve, id)) - }); - break; - case "shuffle": - playbackManager.shuffle(item), getResolveFunction(resolve, id)(); - break; - case "instantmix": - playbackManager.instantMix(item), getResolveFunction(resolve, id)(); - break; - case "delete": - deleteItem(apiClient, item).then(getResolveFunction(resolve, id, !0, !0), getResolveFunction(resolve, id)); - break; - case "share": - navigator.share({ - title: item.Name, - text: item.Overview, - url: "https://github.com/jellyfin/jellyfin" - }); - break; - case "album": - appRouter.showItem(item.AlbumId, item.ServerId), getResolveFunction(resolve, id)(); - break; - case "artist": - appRouter.showItem(item.ArtistItems[0].Id, item.ServerId), getResolveFunction(resolve, id)(); - break; - case "playallfromhere": - case "queueallfromhere": - getResolveFunction(resolve, id)(); - break; - case "convert": - require(["syncDialog"], function(syncDialog) { - syncDialog.showMenu({ - items: [item], - serverId: serverId, - mode: "convert" - }) - }), getResolveFunction(resolve, id)(); - break; - case "sync": - require(["syncDialog"], function(syncDialog) { - syncDialog.showMenu({ - items: [item], - serverId: serverId, - mode: "sync" - }) - }), getResolveFunction(resolve, id)(); - break; - case "synclocal": - require(["syncDialog"], function(syncDialog) { - syncDialog.showMenu({ - items: [item], - serverId: serverId, - mode: "download" - }) - }), getResolveFunction(resolve, id)(); - break; - case "removefromplaylist": + case 'shuffle': + { + playbackManager.shuffle(item); + getResolveFunction(resolve, id)(); + break; + } + case 'instantmix': + { + playbackManager.instantMix(item); + getResolveFunction(resolve, id)(); + break; + } + case 'delete': + { + deleteItem(apiClient, item).then(getResolveFunction(resolve, id, true, true), getResolveFunction(resolve, id)); + break; + } + case 'share': + { + navigator.share({ + title: item.Name, + text: item.Overview, + + // TODO: Make this the server's external url + url: 'https://emby.media' + }); + break; + } + case 'album': + { + appRouter.showItem(item.AlbumId, item.ServerId); + getResolveFunction(resolve, id)(); + break; + } + case 'artist': + { + appRouter.showItem(item.ArtistItems[0].Id, item.ServerId); + getResolveFunction(resolve, id)(); + break; + } + case 'playallfromhere': + { + getResolveFunction(resolve, id)(); + break; + } + case 'queueallfromhere': + { + getResolveFunction(resolve, id)(); + break; + } + case 'convert': + { + require(['syncDialog'], function (syncDialog) { + syncDialog.showMenu({ + items: [item], + serverId: serverId, + mode: 'convert' + }); + }); + getResolveFunction(resolve, id)(); + break; + } + case 'sync': + { + require(['syncDialog'], function (syncDialog) { + syncDialog.showMenu({ + items: [item], + serverId: serverId, + mode: 'sync' + }); + }); + getResolveFunction(resolve, id)(); + break; + } + case 'synclocal': + { + require(['syncDialog'], function (syncDialog) { + syncDialog.showMenu({ + items: [item], + serverId: serverId, + mode: 'download' + }); + }); + getResolveFunction(resolve, id)(); + break; + } + case 'removefromplaylist': + apiClient.ajax({ - url: apiClient.getUrl("Playlists/" + options.playlistId + "/Items", { - EntryIds: [item.PlaylistItemId].join(",") + + url: apiClient.getUrl('Playlists/' + options.playlistId + '/Items', { + EntryIds: [item.PlaylistItemId].join(',') }), - type: "DELETE" - }).then(function() { - getResolveFunction(resolve, id, !0)() + + type: 'DELETE' + + }).then(function () { + + getResolveFunction(resolve, id, true)(); }); + break; - case "removefromcollection": + case 'removefromcollection': + apiClient.ajax({ type: "DELETE", url: apiClient.getUrl("Collections/" + options.collectionId + "/Items", { - Ids: [item.Id].join(",") + + Ids: [item.Id].join(',') }) - }).then(function() { - getResolveFunction(resolve, id, !0)() + + }).then(function () { + + getResolveFunction(resolve, id, true)(); }); + break; - case "canceltimer": + case 'canceltimer': deleteTimer(apiClient, item, resolve, id); break; - case "cancelseriestimer": + case 'cancelseriestimer': deleteSeriesTimer(apiClient, item, resolve, id); break; default: - reject() + reject(); + break; } - }) + }); } function deleteTimer(apiClient, item, resolve, command) { - require(["recordingHelper"], function(recordingHelper) { + + require(['recordingHelper'], function (recordingHelper) { + var timerId = item.TimerId || item.Id; - recordingHelper.cancelTimerWithConfirmation(timerId, item.ServerId).then(function() { - getResolveFunction(resolve, command, !0)() - }) - }) + + recordingHelper.cancelTimerWithConfirmation(timerId, item.ServerId).then(function () { + getResolveFunction(resolve, command, true)(); + }); + }); } function deleteSeriesTimer(apiClient, item, resolve, command) { - require(["recordingHelper"], function(recordingHelper) { - recordingHelper.cancelSeriesTimerWithConfirmation(item.Id, item.ServerId).then(function() { - getResolveFunction(resolve, command, !0)() - }) - }) + + require(['recordingHelper'], function (recordingHelper) { + + recordingHelper.cancelSeriesTimerWithConfirmation(item.Id, item.ServerId).then(function () { + getResolveFunction(resolve, command, true)(); + }); + }); } function play(item, resume, queue, queueNext) { - var method = queue ? queueNext ? "queueNext" : "queue" : "play", - startPosition = 0; - resume && item.UserData && item.UserData.PlaybackPositionTicks && (startPosition = item.UserData.PlaybackPositionTicks), "Program" === item.Type ? playbackManager[method]({ - ids: [item.ChannelId], - startPositionTicks: startPosition, - serverId: item.ServerId - }) : playbackManager[method]({ - items: [item], - startPositionTicks: startPosition - }) + + var method = queue ? (queueNext ? 'queueNext' : 'queue') : 'play'; + + var startPosition = 0; + if (resume && item.UserData && item.UserData.PlaybackPositionTicks) { + startPosition = item.UserData.PlaybackPositionTicks; + } + + if (item.Type === 'Program') { + playbackManager[method]({ + ids: [item.ChannelId], + startPositionTicks: startPosition, + serverId: item.ServerId + }); + } else { + playbackManager[method]({ + items: [item], + startPositionTicks: startPosition + }); + } } function editItem(apiClient, item) { - return new Promise(function(resolve, reject) { + + return new Promise(function (resolve, reject) { + var serverId = apiClient.serverInfo().Id; - "Timer" === item.Type ? require(["recordingEditor"], function(recordingEditor) { - recordingEditor.show(item.Id, serverId).then(resolve, reject) - }) : "SeriesTimer" === item.Type ? require(["seriesRecordingEditor"], function(recordingEditor) { - recordingEditor.show(item.Id, serverId).then(resolve, reject) - }) : require(["metadataEditor"], function(metadataEditor) { - metadataEditor.show(item.Id, serverId).then(resolve, reject) - }) - }) + + if (item.Type === 'Timer') { + require(['recordingEditor'], function (recordingEditor) { + + recordingEditor.show(item.Id, serverId).then(resolve, reject); + }); + } else if (item.Type === 'SeriesTimer') { + require(['seriesRecordingEditor'], function (recordingEditor) { + + recordingEditor.show(item.Id, serverId).then(resolve, reject); + }); + } else { + require(['metadataEditor'], function (metadataEditor) { + + metadataEditor.show(item.Id, serverId).then(resolve, reject); + }); + } + }); } function deleteItem(apiClient, item) { - return new Promise(function(resolve, reject) { - require(["deleteHelper"], function(deleteHelper) { + + return new Promise(function (resolve, reject) { + + require(['deleteHelper'], function (deleteHelper) { + deleteHelper.deleteItem({ + item: item, - navigate: !1 - }).then(function() { - resolve(!0) - }, reject) - }) - }) + navigate: false + + }).then(function () { + + resolve(true); + + }, reject); + + }); + }); } function refresh(apiClient, item) { - require(["refreshDialog"], function(refreshDialog) { + + require(['refreshDialog'], function (refreshDialog) { new refreshDialog({ itemIds: [item.Id], serverId: apiClient.serverInfo().Id, - mode: "CollectionFolder" === item.Type ? "scan" : null - }).show() - }) + mode: item.Type === 'CollectionFolder' ? 'scan' : null + }).show(); + }); } function show(options) { + var commands = getCommands(options); - return commands.length ? actionsheet.show({ + + if (!commands.length) { + return Promise.reject(); + } + + return actionsheet.show({ + items: commands, positionTo: options.positionTo, - resolveOnClick: ["share"] - }).then(function(id) { - return executeCommand(options.item, id, options) - }) : Promise.reject() + + resolveOnClick: ['share'] + + }).then(function (id) { + return executeCommand(options.item, id, options); + }); } + return { getCommands: getCommands, show: show - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/itemhelper.js b/src/bower_components/emby-webcomponents/itemhelper.js index 4dc99ca3c6..6d22fd4d2b 100644 --- a/src/bower_components/emby-webcomponents/itemhelper.js +++ b/src/bower_components/emby-webcomponents/itemhelper.js @@ -1,92 +1,366 @@ -define(["apphost", "globalize"], function(appHost, globalize) { - "use strict"; +define(['apphost', 'globalize'], function (appHost, globalize) { + 'use strict'; function getDisplayName(item, options) { - if (!item) throw new Error("null item passed into getDisplayName"); - options = options || {}, "Timer" === item.Type && (item = item.ProgramInfo || item); - var name = ("Program" !== item.Type && "Recording" !== item.Type || !item.IsSeries && !item.EpisodeTitle ? item.Name : item.EpisodeTitle) || ""; - if ("TvChannel" === item.Type) return item.ChannelNumber ? item.ChannelNumber + " " + name : name; - if ("Episode" === item.Type && 0 === item.ParentIndexNumber) name = globalize.translate("sharedcomponents#ValueSpecialEpisodeName", name); - else if (("Episode" === item.Type || "Program" === item.Type) && null != item.IndexNumber && null != item.ParentIndexNumber && !1 !== options.includeIndexNumber) { - var displayIndexNumber = item.IndexNumber, - number = displayIndexNumber, - nameSeparator = " - "; - !1 !== options.includeParentInfo ? number = "S" + item.ParentIndexNumber + ":E" + number : nameSeparator = ". ", item.IndexNumberEnd && (displayIndexNumber = item.IndexNumberEnd, number += "-" + displayIndexNumber), number && (name = name ? number + nameSeparator + name : number) + + if (!item) { + throw new Error("null item passed into getDisplayName"); } - return name + + options = options || {}; + + if (item.Type === 'Timer') { + item = item.ProgramInfo || item; + } + + var name = ((item.Type === 'Program' || item.Type === 'Recording') && (item.IsSeries || item.EpisodeTitle) ? item.EpisodeTitle : item.Name) || ''; + + if (item.Type === "TvChannel") { + + if (item.ChannelNumber) { + return item.ChannelNumber + ' ' + name; + } + return name; + } + if (/*options.isInlineSpecial &&*/ item.Type === "Episode" && item.ParentIndexNumber === 0) { + + name = globalize.translate('sharedcomponents#ValueSpecialEpisodeName', name); + + } else if ((item.Type === "Episode" || item.Type === 'Program') && item.IndexNumber != null && item.ParentIndexNumber != null && options.includeIndexNumber !== false) { + + var displayIndexNumber = item.IndexNumber; + + var number = displayIndexNumber; + var nameSeparator = " - "; + + if (options.includeParentInfo !== false) { + number = "S" + item.ParentIndexNumber + ":E" + number; + } else { + nameSeparator = ". "; + } + + if (item.IndexNumberEnd) { + + displayIndexNumber = item.IndexNumberEnd; + number += "-" + displayIndexNumber; + } + + if (number) { + name = name ? (number + nameSeparator + name) : number; + } + } + + return name; } function supportsAddingToCollection(item) { - var invalidTypes = ["Genre", "MusicGenre", "Studio", "GameGenre", "UserView", "CollectionFolder", "Audio", "Program", "Timer", "SeriesTimer"]; - return ("Recording" !== item.Type || "Completed" === item.Status) && (!item.CollectionType && -1 === invalidTypes.indexOf(item.Type) && "Photo" !== item.MediaType && !isLocalItem(item)) + + var invalidTypes = ['Genre', 'MusicGenre', 'Studio', 'GameGenre', 'UserView', 'CollectionFolder', 'Audio', 'Program', 'Timer', 'SeriesTimer']; + + if (item.Type === 'Recording') { + if (item.Status !== 'Completed') { + return false; + } + } + + return !item.CollectionType && invalidTypes.indexOf(item.Type) === -1 && item.MediaType !== 'Photo' && !isLocalItem(item); } function supportsAddingToPlaylist(item) { - return "Program" !== item.Type && ("TvChannel" !== item.Type && ("Timer" !== item.Type && ("SeriesTimer" !== item.Type && ("Photo" !== item.MediaType && (("Recording" !== item.Type || "Completed" === item.Status) && (!isLocalItem(item) && ("livetv" !== item.CollectionType && (item.MediaType || item.IsFolder || "Genre" === item.Type || "MusicGenre" === item.Type || "MusicArtist" === item.Type)))))))) + + if (item.Type === 'Program') { + return false; + } + if (item.Type === 'TvChannel') { + return false; + } + if (item.Type === 'Timer') { + return false; + } + if (item.Type === 'SeriesTimer') { + return false; + } + if (item.MediaType === 'Photo') { + return false; + } + + if (item.Type === 'Recording') { + if (item.Status !== 'Completed') { + return false; + } + } + + if (isLocalItem(item)) { + return false; + } + if (item.CollectionType === 'livetv') { + return false; + } + + return item.MediaType || item.IsFolder || item.Type === "Genre" || item.Type === "MusicGenre" || item.Type === "MusicArtist"; } function canEdit(user, item) { + var itemType = item.Type; - return "UserRootFolder" !== itemType && "UserView" !== itemType && ("Program" !== itemType && ("Timer" !== itemType && ("SeriesTimer" !== itemType && (("Recording" !== item.Type || "Completed" === item.Status) && (!isLocalItem(item) && user.Policy.IsAdministrator))))) + + if (itemType === "UserRootFolder" || /*itemType == "CollectionFolder" ||*/ itemType === "UserView") { + return false; + } + + if (itemType === 'Program') { + return false; + } + + if (itemType === 'Timer') { + return false; + } + + if (itemType === 'SeriesTimer') { + return false; + } + + if (item.Type === 'Recording') { + if (item.Status !== 'Completed') { + return false; + } + } + + if (isLocalItem(item)) { + return false; + } + + return user.Policy.IsAdministrator; } function isLocalItem(item) { - return !(!item || !item.Id || 0 !== item.Id.indexOf("local")) + + if (item && item.Id && item.Id.indexOf('local') === 0) { + return true; + } + + return false; } + return { getDisplayName: getDisplayName, supportsAddingToCollection: supportsAddingToCollection, supportsAddingToPlaylist: supportsAddingToPlaylist, isLocalItem: isLocalItem, - canIdentify: function(user, item) { + + canIdentify: function (user, item) { + var itemType = item.Type; - return !("Movie" !== itemType && "Trailer" !== itemType && "Series" !== itemType && "Game" !== itemType && "BoxSet" !== itemType && "Person" !== itemType && "Book" !== itemType && "MusicAlbum" !== itemType && "MusicArtist" !== itemType && "MusicVideo" !== itemType || !user.Policy.IsAdministrator || isLocalItem(item)) + + if (itemType === "Movie" || + itemType === "Trailer" || + itemType === "Series" || + itemType === "Game" || + itemType === "BoxSet" || + itemType === "Person" || + itemType === "Book" || + itemType === "MusicAlbum" || + itemType === "MusicArtist" || + itemType === "MusicVideo") { + + if (user.Policy.IsAdministrator) { + + if (!isLocalItem(item)) { + return true; + } + } + } + + return false; }, + canEdit: canEdit, - canEditImages: function(user, item) { + + canEditImages: function (user, item) { + var itemType = item.Type; - return "Photo" !== item.MediaType && ("UserView" === itemType ? !!user.Policy.IsAdministrator : ("Recording" !== item.Type || "Completed" === item.Status) && ("Timer" !== itemType && "SeriesTimer" !== itemType && canEdit(user, item) && !isLocalItem(item))) - }, - canSync: function(user, item) { - return !(user && !user.Policy.EnableContentDownloading) && (!isLocalItem(item) && item.SupportsSync) - }, - canShare: function(item, user) { - return "Program" !== item.Type && ("TvChannel" !== item.Type && ("Timer" !== item.Type && ("SeriesTimer" !== item.Type && (("Recording" !== item.Type || "Completed" === item.Status) && (!isLocalItem(item) && (user.Policy.EnablePublicSharing && appHost.supports("sharing"))))))) - }, - enableDateAddedDisplay: function(item) { - return !item.IsFolder && item.MediaType && "Program" !== item.Type && "TvChannel" !== item.Type && "Trailer" !== item.Type - }, - canMarkPlayed: function(item) { - if ("Program" === item.Type) return !1; - if ("Video" === item.MediaType) { - if ("TvChannel" !== item.Type) return !0 - } else if ("Audio" === item.MediaType) { - if ("AudioPodcast" === item.Type) return !0; - if ("AudioBook" === item.Type) return !0 + + if (item.MediaType === 'Photo') { + return false; } - return "Series" === item.Type || "Season" === item.Type || "BoxSet" === item.Type || "Game" === item.MediaType || "Book" === item.MediaType || "Recording" === item.MediaType + + if (itemType === 'UserView') { + if (user.Policy.IsAdministrator) { + + return true; + } + + return false; + } + + if (item.Type === 'Recording') { + if (item.Status !== 'Completed') { + return false; + } + } + + return itemType !== 'Timer' && itemType !== 'SeriesTimer' && canEdit(user, item) && !isLocalItem(item); }, - canRate: function(item) { - return "Program" !== item.Type && "Timer" !== item.Type && "SeriesTimer" !== item.Type && "CollectionFolder" !== item.Type && "UserView" !== item.Type && "Channel" !== item.Type && "Season" !== item.Type && "Studio" !== item.Type && !!item.UserData + + canSync: function (user, item) { + + if (user && !user.Policy.EnableContentDownloading) { + return false; + } + + if (isLocalItem(item)) { + return false; + } + + return item.SupportsSync; }, - canConvert: function(item, user) { - if (!user.Policy.EnableMediaConversion) return !1; - if (isLocalItem(item)) return !1; + + canShare: function (item, user) { + + if (item.Type === 'Program') { + return false; + } + if (item.Type === 'TvChannel') { + return false; + } + if (item.Type === 'Timer') { + return false; + } + if (item.Type === 'SeriesTimer') { + return false; + } + if (item.Type === 'Recording') { + if (item.Status !== 'Completed') { + return false; + } + } + if (isLocalItem(item)) { + return false; + } + return user.Policy.EnablePublicSharing && appHost.supports('sharing'); + }, + + enableDateAddedDisplay: function (item) { + return !item.IsFolder && item.MediaType && item.Type !== 'Program' && item.Type !== 'TvChannel' && item.Type !== 'Trailer'; + }, + + canMarkPlayed: function (item) { + + if (item.Type === 'Program') { + return false; + } + + if (item.MediaType === 'Video') { + if (item.Type !== 'TvChannel') { + return true; + } + } + + else 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; + }, + + canRate: function (item) { + + if (item.Type === 'Program' || item.Type === 'Timer' || item.Type === 'SeriesTimer' || item.Type === 'CollectionFolder' || item.Type === 'UserView' || item.Type === 'Channel') { + return false; + } + + return true; + }, + + canConvert: function (item, user) { + + if (!user.Policy.EnableMediaConversion) { + return false; + } + + if (isLocalItem(item)) { + return false; + } + var mediaType = item.MediaType; - if ("Book" === mediaType || "Photo" === mediaType || "Game" === mediaType || "Audio" === mediaType) return !1; - if ("livetv" === item.CollectionType) return !1; - var type = item.Type; - return "Channel" !== type && "Person" !== type && "Year" !== type && "Program" !== type && "Timer" !== type && "SeriesTimer" !== type && (!("Virtual" === item.LocationType && !item.IsFolder) && !item.IsPlaceHolder) - }, - canRefreshMetadata: function(item, user) { - if (user.Policy.IsAdministrator) { - if ("livetv" === item.CollectionType) return !1; - if ("Timer" !== item.Type && "SeriesTimer" !== item.Type && "Program" !== item.Type && "TvChannel" !== item.Type && ("Recording" !== item.Type || "Completed" === item.Status) && !isLocalItem(item)) return !0 + if (mediaType === 'Book' || mediaType === 'Photo' || mediaType === 'Game' || mediaType === 'Audio') { + return false; } - return !1 + + var collectionType = item.CollectionType; + if (collectionType === 'livetv') { + return false; + } + + var type = item.Type; + if (type === 'Channel' || type === 'Person' || type === 'Year' || type === 'Program' || type === 'Timer' || type === 'SeriesTimer') { + return false; + } + + if (item.LocationType === 'Virtual' && !item.IsFolder) { + return false; + } + + if (item.IsPlaceHolder) { + return false; + } + + return true; }, - supportsMediaSourceSelection: function(item) { - return "Video" === item.MediaType && ("TvChannel" !== item.Type && (!(!item.MediaSources || 1 === item.MediaSources.length && "Placeholder" === item.MediaSources[0].Type) && (!1 !== item.EnableMediaSourceDisplay && (null != item.EnableMediaSourceDisplay || !item.SourceType || "Library" === item.SourceType)))) + + canRefreshMetadata: function (item, user) { + + if (user.Policy.IsAdministrator) { + + var collectionType = item.CollectionType; + if (collectionType === 'livetv') { + return false; + } + + if (item.Type !== 'Timer' && item.Type !== 'SeriesTimer' && item.Type !== 'Program' && item.Type !== 'TvChannel' && !(item.Type === 'Recording' && item.Status !== 'Completed')) { + + if (!isLocalItem(item)) { + return true; + } + } + } + + return false; + }, + + supportsMediaSourceSelection: function (item) { + + if (item.MediaType !== 'Video') { + return false; + } + if (item.Type === 'TvChannel') { + return false; + } + if (!item.MediaSources || (item.MediaSources.length === 1 && item.MediaSources[0].Type === 'Placeholder')) { + return false; + } + if (item.EnableMediaSourceDisplay === false) { + return false; + } + if (item.EnableMediaSourceDisplay == null && item.SourceType && item.SourceType !== 'Library') { + return false; + } + + return true; } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/itemidentifier/itemidentifier.js b/src/bower_components/emby-webcomponents/itemidentifier/itemidentifier.js index 3024bee3d1..0107ca4097 100644 --- a/src/bower_components/emby-webcomponents/itemidentifier/itemidentifier.js +++ b/src/bower_components/emby-webcomponents/itemidentifier/itemidentifier.js @@ -1,192 +1,528 @@ -define(["dialogHelper", "loading", "connectionManager", "require", "globalize", "scrollHelper", "layoutManager", "focusManager", "browser", "emby-input", "emby-checkbox", "paper-icon-button-light", "css!./../formdialog", "material-icons", "cardStyle"], function(dialogHelper, loading, connectionManager, require, globalize, scrollHelper, layoutManager, focusManager, browser) { - "use strict"; +define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize', 'scrollHelper', 'layoutManager', 'focusManager', 'browser', 'emby-input', 'emby-checkbox', 'paper-icon-button-light', 'css!./../formdialog', 'material-icons', 'cardStyle'], function (dialogHelper, loading, connectionManager, require, globalize, scrollHelper, layoutManager, focusManager, browser) { + 'use strict'; + + var currentItem; + var currentItemType; + var currentServerId; + var currentResolve; + var currentReject; + var hasChanges = false; + var currentSearchResult; function getApiClient() { - return connectionManager.getApiClient(currentServerId) + return connectionManager.getApiClient(currentServerId); } function searchForIdentificationResults(page) { - var i, length, value, lookupInfo = { - ProviderIds: {} - }, - identifyField = page.querySelectorAll(".identifyField"); - for (i = 0, length = identifyField.length; i < length; i++)(value = identifyField[i].value) && ("number" === identifyField[i].type && (value = parseInt(value)), lookupInfo[identifyField[i].getAttribute("data-lookup")] = value); - var hasId = !1, - txtLookupId = page.querySelectorAll(".txtLookupId"); - for (i = 0, length = txtLookupId.length; i < length; i++) value = txtLookupId[i].value, value && (hasId = !0), lookupInfo.ProviderIds[txtLookupId[i].getAttribute("data-providerkey")] = value; - if (!hasId && !lookupInfo.Name) return void require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#PleaseEnterNameOrId")) - }); - currentItem && currentItem.GameSystem && (lookupInfo.GameSystem = currentItem.GameSystem), lookupInfo = { + + var lookupInfo = { + ProviderIds: {} + }; + + var i, length; + var identifyField = page.querySelectorAll('.identifyField'); + var value; + for (i = 0, length = identifyField.length; i < length; i++) { + + value = identifyField[i].value; + + if (value) { + + if (identifyField[i].type === 'number') { + value = parseInt(value); + } + + lookupInfo[identifyField[i].getAttribute('data-lookup')] = value; + } + } + + var hasId = false; + + var txtLookupId = page.querySelectorAll('.txtLookupId'); + for (i = 0, length = txtLookupId.length; i < length; i++) { + + value = txtLookupId[i].value; + + if (value) { + hasId = true; + } + lookupInfo.ProviderIds[txtLookupId[i].getAttribute('data-providerkey')] = value; + } + + if (!hasId && !lookupInfo.Name) { + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#PleaseEnterNameOrId')); + }); + return; + } + + if (currentItem && currentItem.GameSystem) { + lookupInfo.GameSystem = currentItem.GameSystem; + } + + lookupInfo = { SearchInfo: lookupInfo - }, currentItem && currentItem.Id ? lookupInfo.ItemId = currentItem.Id : lookupInfo.IncludeDisabledProviders = !0, loading.show(); + }; + + if (currentItem && currentItem.Id) { + lookupInfo.ItemId = currentItem.Id; + } + else { + lookupInfo.IncludeDisabledProviders = true; + } + + loading.show(); + var apiClient = getApiClient(); + apiClient.ajax({ type: "POST", url: apiClient.getUrl("Items/RemoteSearch/" + currentItemType), data: JSON.stringify(lookupInfo), contentType: "application/json", - dataType: "json" - }).then(function(results) { - loading.hide(), showIdentificationSearchResults(page, results) - }) + dataType: 'json' + + }).then(function (results) { + + loading.hide(); + showIdentificationSearchResults(page, results); + }); } function showIdentificationSearchResults(page, results) { - function onSearchImageClick() { - var index = parseInt(this.getAttribute("data-index")), - currentResult = results[index]; - null != currentItem ? showIdentifyOptions(page, currentResult) : finishFindNewDialog(page, currentResult) - } - var identificationSearchResults = page.querySelector(".identificationSearchResults"); - page.querySelector(".popupIdentifyForm").classList.add("hide"), identificationSearchResults.classList.remove("hide"), page.querySelector(".identifyOptionsForm").classList.add("hide"), page.querySelector(".dialogContentInner").classList.remove("dialog-content-centered"); - var i, length, html = ""; + + var identificationSearchResults = page.querySelector('.identificationSearchResults'); + + page.querySelector('.popupIdentifyForm').classList.add('hide'); + identificationSearchResults.classList.remove('hide'); + page.querySelector('.identifyOptionsForm').classList.add('hide'); + page.querySelector('.dialogContentInner').classList.remove('dialog-content-centered'); + + var html = ''; + var i, length; for (i = 0, length = results.length; i < length; i++) { - html += getSearchResultHtml(results[i], i) + + var result = results[i]; + html += getSearchResultHtml(result, i); } - var elem = page.querySelector(".identificationSearchResultList"); + + var elem = page.querySelector('.identificationSearchResultList'); elem.innerHTML = html; - var searchImages = elem.querySelectorAll(".card"); - for (i = 0, length = searchImages.length; i < length; i++) searchImages[i].addEventListener("click", onSearchImageClick); - layoutManager.tv && focusManager.autoFocus(identificationSearchResults) + + function onSearchImageClick() { + var index = parseInt(this.getAttribute('data-index')); + + var currentResult = results[index]; + + if (currentItem != null) { + + showIdentifyOptions(page, currentResult); + } else { + + finishFindNewDialog(page, currentResult); + } + } + + var searchImages = elem.querySelectorAll('.card'); + for (i = 0, length = searchImages.length; i < length; i++) { + + searchImages[i].addEventListener('click', onSearchImageClick); + } + + if (layoutManager.tv) { + focusManager.autoFocus(identificationSearchResults); + } } function finishFindNewDialog(dlg, identifyResult) { - currentSearchResult = identifyResult, hasChanges = !0, loading.hide(), dialogHelper.close(dlg) + currentSearchResult = identifyResult; + hasChanges = true; + loading.hide(); + + dialogHelper.close(dlg); } function showIdentifyOptions(page, identifyResult) { - var identifyOptionsForm = page.querySelector(".identifyOptionsForm"); - page.querySelector(".popupIdentifyForm").classList.add("hide"), page.querySelector(".identificationSearchResults").classList.add("hide"), identifyOptionsForm.classList.remove("hide"), page.querySelector("#chkIdentifyReplaceImages").checked = !0, page.querySelector(".dialogContentInner").classList.add("dialog-content-centered"), currentSearchResult = identifyResult; + + var identifyOptionsForm = page.querySelector('.identifyOptionsForm'); + + page.querySelector('.popupIdentifyForm').classList.add('hide'); + page.querySelector('.identificationSearchResults').classList.add('hide'); + identifyOptionsForm.classList.remove('hide'); + page.querySelector('#chkIdentifyReplaceImages').checked = true; + page.querySelector('.dialogContentInner').classList.add('dialog-content-centered'); + + currentSearchResult = identifyResult; + var lines = []; - lines.push(identifyResult.Name), identifyResult.ProductionYear && lines.push(identifyResult.ProductionYear), identifyResult.GameSystem && lines.push(identifyResult.GameSystem); - var resultHtml = lines.join("
"); - if (identifyResult.ImageUrl) { - resultHtml = '
' + resultHtml + "
" + lines.push(identifyResult.Name); + + if (identifyResult.ProductionYear) { + lines.push(identifyResult.ProductionYear); } - page.querySelector(".selectedSearchResult").innerHTML = resultHtml, focusManager.focus(identifyOptionsForm.querySelector(".btnSubmit")) + + if (identifyResult.GameSystem) { + lines.push(identifyResult.GameSystem); + } + + var resultHtml = lines.join('
'); + + if (identifyResult.ImageUrl) { + var displayUrl = getSearchImageDisplayUrl(identifyResult.ImageUrl, identifyResult.SearchProviderName); + + resultHtml = '
' + resultHtml + '
'; + } + + page.querySelector('.selectedSearchResult').innerHTML = resultHtml; + + focusManager.focus(identifyOptionsForm.querySelector('.btnSubmit')); } function getSearchResultHtml(result, index) { - var padderClass, html = "", - cssClass = "card scalableCard", - cardBoxCssClass = "cardBox"; - if ("Episode" === currentItemType ? (cssClass += " backdropCard backdropCard-scalable", padderClass = "cardPadder-backdrop") : "MusicAlbum" === currentItemType || "MusicArtist" === currentItemType ? (cssClass += " squareCard squareCard-scalable", padderClass = "cardPadder-square") : (cssClass += " portraitCard portraitCard-scalable", padderClass = "cardPadder-portrait"), layoutManager.tv && !browser.slow && (cardBoxCssClass += " cardBox-focustransform"), cardBoxCssClass += " cardBox-bottompadded", layoutManager.tv && (cardBoxCssClass += " card-focuscontent cardBox-withfocuscontent"), html += '" + + if (result.AlbumArtist) { + lines.push(result.AlbumArtist.Name); + } + if (result.ProductionYear) { + lines.push(result.ProductionYear); + } + if (result.GameSystem) { + lines.push(result.GameSystem); + } + + for (var i = 0; i < numLines; i++) { + + if (i === 0) { + html += '
'; + } else { + html += '
'; + } + html += lines[i] || ' '; + html += '
'; + } + + html += '
'; + html += ''; + return html; } function getSearchImageDisplayUrl(url, provider) { - return getApiClient().getUrl("Items/RemoteSearch/Image", { - imageUrl: url, - ProviderName: provider - }) + var apiClient = getApiClient(); + + return apiClient.getUrl("Items/RemoteSearch/Image", { imageUrl: url, ProviderName: provider }); } function submitIdentficationResult(page) { + loading.show(); + var options = { - ReplaceAllImages: page.querySelector("#chkIdentifyReplaceImages").checked - }, - apiClient = getApiClient(); + ReplaceAllImages: page.querySelector('#chkIdentifyReplaceImages').checked + }; + + var apiClient = getApiClient(); + apiClient.ajax({ type: "POST", url: apiClient.getUrl("Items/RemoteSearch/Apply/" + currentItem.Id, options), data: JSON.stringify(currentSearchResult), contentType: "application/json" - }).then(function() { - hasChanges = !0, loading.hide(), dialogHelper.close(page) - }, function() { - loading.hide(), dialogHelper.close(page) - }) + + }).then(function () { + + hasChanges = true; + loading.hide(); + + dialogHelper.close(page); + + }, function () { + + loading.hide(); + + dialogHelper.close(page); + }); } function showIdentificationForm(page, item) { + var apiClient = getApiClient(); - apiClient.getJSON(apiClient.getUrl("Items/" + item.Id + "/ExternalIdInfos")).then(function(idList) { - for (var html = "", providerIds = item.ProviderIds || {}, i = 0, length = idList.length; i < length; i++) { - var idInfo = idList[i], - id = "txtLookup" + idInfo.Key; + + apiClient.getJSON(apiClient.getUrl("Items/" + item.Id + "/ExternalIdInfos")).then(function (idList) { + + var html = ''; + + var providerIds = item.ProviderIds || {}; + + for (var i = 0, length = idList.length; i < length; i++) { + + var idInfo = idList[i]; + + var id = "txtLookup" + idInfo.Key; + html += '
'; - var idLabel = globalize.translate("sharedcomponents#LabelDynamicExternalId").replace("{0}", idInfo.Name); - idInfo.Key; - html += '', html += "
" + + var idLabel = globalize.translate('sharedcomponents#LabelDynamicExternalId').replace('{0}', idInfo.Name); + + var value = providerIds[idInfo.Key] || ''; + + html += ''; + + html += '
'; } - page.querySelector("#txtLookupName").value = "", "Person" === item.Type || "BoxSet" === item.Type ? (page.querySelector(".fldLookupYear").classList.add("hide"), page.querySelector("#txtLookupYear").value = "") : (page.querySelector(".fldLookupYear").classList.remove("hide"), page.querySelector("#txtLookupYear").value = ""), page.querySelector(".identifyProviderIds").innerHTML = html, page.querySelector(".formDialogHeaderTitle").innerHTML = globalize.translate("sharedcomponents#Identify") - }) + + page.querySelector('#txtLookupName').value = ''; + + if (item.Type === "Person" || item.Type === "BoxSet") { + + page.querySelector('.fldLookupYear').classList.add('hide'); + page.querySelector('#txtLookupYear').value = ''; + } else { + + page.querySelector('.fldLookupYear').classList.remove('hide'); + page.querySelector('#txtLookupYear').value = ''; + } + + page.querySelector('.identifyProviderIds').innerHTML = html; + + page.querySelector('.formDialogHeaderTitle').innerHTML = globalize.translate('sharedcomponents#Identify'); + }); } function showEditor(itemId) { - loading.show(), require(["text!./itemidentifier.template.html"], function(template) { + + loading.show(); + + require(['text!./itemidentifier.template.html'], function (template) { + var apiClient = getApiClient(); - apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(item) { - currentItem = item, currentItemType = currentItem.Type; + + apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { + + currentItem = item; + currentItemType = currentItem.Type; + var dialogOptions = { - size: "fullscreen-border", - removeOnClose: !0, - scrollY: !1 + size: 'fullscreen-border', + removeOnClose: true, + scrollY: false }; - layoutManager.tv && (dialogOptions.size = "fullscreen"); + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.classList.add("recordingDialog"); - var html = ""; - html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, dlg.addEventListener("close", onDialogClosed), layoutManager.tv && scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1), dialogHelper.open(dlg), dlg.querySelector(".popupIdentifyForm").addEventListener("submit", function(e) { - return e.preventDefault(), searchForIdentificationResults(dlg), !1 - }), dlg.querySelector(".identifyOptionsForm").addEventListener("submit", function(e) { - return e.preventDefault(), submitIdentficationResult(dlg), !1 - }), dlg.querySelector(".btnCancel").addEventListener("click", function(e) { - dialogHelper.close(dlg) - }), dlg.classList.add("identifyDialog"), showIdentificationForm(dlg, item), loading.hide() - }) - }) + + dlg.classList.add('formDialog'); + dlg.classList.add('recordingDialog'); + + var html = ''; + html += globalize.translateDocument(template, 'sharedcomponents'); + + dlg.innerHTML = html; + + // Has to be assigned a z-index after the call to .open() + dlg.addEventListener('close', onDialogClosed); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); + } + + dialogHelper.open(dlg); + + dlg.querySelector('.popupIdentifyForm').addEventListener('submit', function (e) { + + e.preventDefault(); + searchForIdentificationResults(dlg); + return false; + }); + + dlg.querySelector('.identifyOptionsForm').addEventListener('submit', function (e) { + + e.preventDefault(); + submitIdentficationResult(dlg); + return false; + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function (e) { + + dialogHelper.close(dlg); + }); + + dlg.classList.add('identifyDialog'); + + showIdentificationForm(dlg, item); + loading.hide(); + }); + }); } function onDialogClosed() { - loading.hide(), hasChanges ? currentResolve() : currentReject() + + loading.hide(); + if (hasChanges) { + currentResolve(); + } else { + currentReject(); + } } function showEditorFindNew(itemName, itemYear, itemType, resolveFunc) { - currentItem = null, currentItemType = itemType, require(["text!./itemidentifier.template.html"], function(template) { + + currentItem = null; + currentItemType = itemType; + + require(['text!./itemidentifier.template.html'], function (template) { + var dialogOptions = { - size: "fullscreen-border", - removeOnClose: !0, - scrollY: !1 + size: 'fullscreen-border', + removeOnClose: true, + scrollY: false }; - layoutManager.tv && (dialogOptions.size = "fullscreen"); + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.classList.add("recordingDialog"); - var html = ""; - html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, layoutManager.tv && scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1), dialogHelper.open(dlg), dlg.querySelector(".btnCancel").addEventListener("click", function(e) { - dialogHelper.close(dlg) - }), dlg.querySelector(".popupIdentifyForm").addEventListener("submit", function(e) { - return e.preventDefault(), searchForIdentificationResults(dlg), !1 - }), dlg.addEventListener("close", function() { - loading.hide(), resolveFunc(hasChanges ? currentSearchResult : null) - }), dlg.classList.add("identifyDialog"), showIdentificationFormFindNew(dlg, itemName, itemYear, itemType) - }) + + dlg.classList.add('formDialog'); + dlg.classList.add('recordingDialog'); + + var html = ''; + html += globalize.translateDocument(template, 'sharedcomponents'); + + dlg.innerHTML = html; + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); + } + + dialogHelper.open(dlg); + + dlg.querySelector('.btnCancel').addEventListener('click', function (e) { + + dialogHelper.close(dlg); + }); + + dlg.querySelector('.popupIdentifyForm').addEventListener('submit', function (e) { + + e.preventDefault(); + searchForIdentificationResults(dlg); + return false; + }); + + dlg.addEventListener('close', function () { + + loading.hide(); + var foundItem = hasChanges ? currentSearchResult : null; + + resolveFunc(foundItem); + }); + + dlg.classList.add('identifyDialog'); + + showIdentificationFormFindNew(dlg, itemName, itemYear, itemType); + }); } function showIdentificationFormFindNew(dlg, itemName, itemYear, itemType) { - dlg.querySelector("#txtLookupName").value = itemName, "Person" === itemType || "BoxSet" === itemType ? (dlg.querySelector(".fldLookupYear").classList.add("hide"), dlg.querySelector("#txtLookupYear").value = "") : (dlg.querySelector(".fldLookupYear").classList.remove("hide"), dlg.querySelector("#txtLookupYear").value = itemYear), dlg.querySelector(".formDialogHeaderTitle").innerHTML = globalize.translate("sharedcomponents#Search") - } - var currentItem, currentItemType, currentServerId, currentResolve, currentReject, currentSearchResult, hasChanges = !1; - return { - show: function(itemId, serverId) { - return new Promise(function(resolve, reject) { - currentResolve = resolve, currentReject = reject, currentServerId = serverId, hasChanges = !1, showEditor(itemId) - }) - }, - showFindNew: function(itemName, itemYear, itemType, serverId) { - return new Promise(function(resolve, reject) { - currentServerId = serverId, hasChanges = !1, showEditorFindNew(itemName, itemYear, itemType, resolve) - }) + + dlg.querySelector('#txtLookupName').value = itemName; + + if (itemType === "Person" || itemType === "BoxSet") { + + dlg.querySelector('.fldLookupYear').classList.add('hide'); + dlg.querySelector('#txtLookupYear').value = ''; + + } else { + + dlg.querySelector('.fldLookupYear').classList.remove('hide'); + dlg.querySelector('#txtLookupYear').value = itemYear; } + + dlg.querySelector('.formDialogHeaderTitle').innerHTML = globalize.translate('sharedcomponents#Search'); } + + return { + show: function (itemId, serverId) { + + return new Promise(function (resolve, reject) { + + currentResolve = resolve; + currentReject = reject; + currentServerId = serverId; + hasChanges = false; + + showEditor(itemId); + }); + }, + + showFindNew: function (itemName, itemYear, itemType, serverId) { + + return new Promise(function (resolve, reject) { + + currentServerId = serverId; + + hasChanges = false; + showEditorFindNew(itemName, itemYear, itemType, resolve); + }); + } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/itemsrefresher.js b/src/bower_components/emby-webcomponents/itemsrefresher.js index 43a7a3213d..3bdd61236d 100644 --- a/src/bower_components/emby-webcomponents/itemsrefresher.js +++ b/src/bower_components/emby-webcomponents/itemsrefresher.js @@ -1,112 +1,284 @@ -define(["playbackManager", "serverNotifications", "events"], function(playbackManager, serverNotifications, events) { - "use strict"; +define(['playbackManager', 'serverNotifications', 'events'], function (playbackManager, serverNotifications, events) { + 'use strict'; function onUserDataChanged(e, apiClient, userData) { - var instance = this, - eventsToMonitor = getEventsToMonitor(instance); - 1 !== eventsToMonitor.indexOf("markfavorite") ? instance.notifyRefreshNeeded() : -1 !== eventsToMonitor.indexOf("markplayed") && instance.notifyRefreshNeeded() + + var instance = this; + + var eventsToMonitor = getEventsToMonitor(instance); + + // TODO: Check user data change reason? + if (eventsToMonitor.indexOf('markfavorite') !== -1) { + + instance.notifyRefreshNeeded(); + } + else if (eventsToMonitor.indexOf('markplayed') !== -1) { + + instance.notifyRefreshNeeded(); + } } function getEventsToMonitor(instance) { - var options = instance.options, - monitor = options ? options.monitorEvents : null; - return monitor ? monitor.split(",") : [] + + var options = instance.options; + var monitor = options ? options.monitorEvents : null; + if (monitor) { + return monitor.split(','); + } + + return []; } function onTimerCreated(e, apiClient, data) { + var instance = this; - if (-1 !== getEventsToMonitor(instance).indexOf("timers")) return void instance.notifyRefreshNeeded() + + if (getEventsToMonitor(instance).indexOf('timers') !== -1) { + + instance.notifyRefreshNeeded(); + return; + } } function onSeriesTimerCreated(e, apiClient, data) { + var instance = this; - if (-1 !== getEventsToMonitor(instance).indexOf("seriestimers")) return void instance.notifyRefreshNeeded() + if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) { + + instance.notifyRefreshNeeded(); + return; + } } function onTimerCancelled(e, apiClient, data) { var instance = this; - if (-1 !== getEventsToMonitor(instance).indexOf("timers")) return void instance.notifyRefreshNeeded() + + if (getEventsToMonitor(instance).indexOf('timers') !== -1) { + + instance.notifyRefreshNeeded(); + return; + } } function onSeriesTimerCancelled(e, apiClient, data) { + var instance = this; - if (-1 !== getEventsToMonitor(instance).indexOf("seriestimers")) return void instance.notifyRefreshNeeded() + if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) { + + instance.notifyRefreshNeeded(); + return; + } } function onLibraryChanged(e, apiClient, data) { - var instance = this, - eventsToMonitor = getEventsToMonitor(instance); - if (-1 === eventsToMonitor.indexOf("seriestimers") && -1 === eventsToMonitor.indexOf("timers")) { - var itemsAdded = data.ItemsAdded || [], - itemsRemoved = data.ItemsRemoved || []; - if (itemsAdded.length || itemsRemoved.length) { - var options = instance.options || {}, - parentId = options.parentId; - if (parentId) { - var foldersAddedTo = data.FoldersAddedTo || [], - foldersRemovedFrom = data.FoldersRemovedFrom || [], - collectionFolders = data.CollectionFolders || []; - if (-1 === foldersAddedTo.indexOf(parentId) && -1 === foldersRemovedFrom.indexOf(parentId) && -1 === collectionFolders.indexOf(parentId)) return - } - instance.notifyRefreshNeeded() + + var instance = this; + var eventsToMonitor = getEventsToMonitor(instance); + if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) { + + // yes this is an assumption + return; + } + + var itemsAdded = data.ItemsAdded || []; + var itemsRemoved = data.ItemsRemoved || []; + if (!itemsAdded.length && !itemsRemoved.length) { + return; + } + + var options = instance.options || {}; + var parentId = options.parentId; + if (parentId) { + var foldersAddedTo = data.FoldersAddedTo || []; + var foldersRemovedFrom = data.FoldersRemovedFrom || []; + var collectionFolders = data.CollectionFolders || []; + + if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) { + return; + } + } + + instance.notifyRefreshNeeded(); + } + + function onPlaybackStopped(e, stopInfo) { + + var instance = this; + + var state = stopInfo.state; + + var eventsToMonitor = getEventsToMonitor(instance); + if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') { + + if (eventsToMonitor.indexOf('videoplayback') !== -1) { + + instance.notifyRefreshNeeded(true); + return; + } + } + + else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') { + + if (eventsToMonitor.indexOf('audioplayback') !== -1) { + + instance.notifyRefreshNeeded(true); + return; } } } - function onPlaybackStopped(e, stopInfo) { - var instance = this, - state = stopInfo.state, - eventsToMonitor = getEventsToMonitor(instance); - if (state.NowPlayingItem && "Video" === state.NowPlayingItem.MediaType) { - if (-1 !== eventsToMonitor.indexOf("videoplayback")) return void instance.notifyRefreshNeeded(!0) - } else if (state.NowPlayingItem && "Audio" === state.NowPlayingItem.MediaType && -1 !== eventsToMonitor.indexOf("audioplayback")) return void instance.notifyRefreshNeeded(!0) - } - function addNotificationEvent(instance, name, handler, owner) { + var localHandler = handler.bind(instance); - owner = owner || serverNotifications, events.on(owner, name, localHandler), instance["event_" + name] = localHandler + owner = owner || serverNotifications; + events.on(owner, name, localHandler); + instance['event_' + name] = localHandler; } function removeNotificationEvent(instance, name, owner) { - var handler = instance["event_" + name]; - handler && (owner = owner || serverNotifications, events.off(owner, name, handler), instance["event_" + name] = null) + + var handler = instance['event_' + name]; + if (handler) { + owner = owner || serverNotifications; + events.off(owner, name, handler); + instance['event_' + name] = null; + } } function ItemsRefresher(options) { - this.options = options || {}, addNotificationEvent(this, "UserDataChanged", onUserDataChanged), addNotificationEvent(this, "TimerCreated", onTimerCreated), addNotificationEvent(this, "SeriesTimerCreated", onSeriesTimerCreated), addNotificationEvent(this, "TimerCancelled", onTimerCancelled), addNotificationEvent(this, "SeriesTimerCancelled", onSeriesTimerCancelled), addNotificationEvent(this, "LibraryChanged", onLibraryChanged), addNotificationEvent(this, "playbackstop", onPlaybackStopped, playbackManager) + + this.options = options || {}; + + addNotificationEvent(this, 'UserDataChanged', onUserDataChanged); + addNotificationEvent(this, 'TimerCreated', onTimerCreated); + addNotificationEvent(this, 'SeriesTimerCreated', onSeriesTimerCreated); + addNotificationEvent(this, 'TimerCancelled', onTimerCancelled); + addNotificationEvent(this, 'SeriesTimerCancelled', onSeriesTimerCancelled); + addNotificationEvent(this, 'LibraryChanged', onLibraryChanged); + addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager); } + ItemsRefresher.prototype.pause = function () { + + clearRefreshInterval(this, true); + + this.paused = true; + }; + + ItemsRefresher.prototype.resume = function (options) { + + this.paused = false; + + var refreshIntervalEndTime = this.refreshIntervalEndTime; + if (refreshIntervalEndTime) { + + var remainingMs = refreshIntervalEndTime - new Date().getTime(); + if (remainingMs > 0 && !this.needsRefresh) { + + resetRefreshInterval(this, remainingMs); + + } else { + this.needsRefresh = true; + this.refreshIntervalEndTime = null; + } + } + + if (this.needsRefresh || (options && options.refresh)) { + return this.refreshItems(); + } + + return Promise.resolve(); + }; + + ItemsRefresher.prototype.refreshItems = function () { + + if (!this.fetchData) { + return Promise.resolve(); + } + + if (this.paused) { + this.needsRefresh = true; + return Promise.resolve(); + } + + this.needsRefresh = false; + + return this.fetchData().then(onDataFetched.bind(this)); + }; + + ItemsRefresher.prototype.notifyRefreshNeeded = function (isInForeground) { + + if (this.paused) { + this.needsRefresh = true; + return; + } + + var timeout = this.refreshTimeout; + if (timeout) { + clearTimeout(timeout); + } + + if (isInForeground === true) { + this.refreshItems(); + } else { + this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000); + } + }; + function clearRefreshInterval(instance, isPausing) { - instance.refreshInterval && (clearInterval(instance.refreshInterval), instance.refreshInterval = null, isPausing || (instance.refreshIntervalEndTime = null)) + + if (instance.refreshInterval) { + + clearInterval(instance.refreshInterval); + instance.refreshInterval = null; + + if (!isPausing) { + instance.refreshIntervalEndTime = null; + } + } } function resetRefreshInterval(instance, intervalMs) { - if (clearRefreshInterval(instance), !intervalMs) { + + clearRefreshInterval(instance); + + if (!intervalMs) { var options = instance.options; - options && (intervalMs = options.refreshIntervalMs) + if (options) { + intervalMs = options.refreshIntervalMs; + } + } + + if (intervalMs) { + instance.refreshInterval = setInterval(instance.notifyRefreshNeeded.bind(instance), intervalMs); + instance.refreshIntervalEndTime = new Date().getTime() + intervalMs; } - intervalMs && (instance.refreshInterval = setInterval(instance.notifyRefreshNeeded.bind(instance), intervalMs), instance.refreshIntervalEndTime = (new Date).getTime() + intervalMs) } function onDataFetched(result) { - resetRefreshInterval(this), this.afterRefresh && this.afterRefresh(result) - } - return ItemsRefresher.prototype.pause = function() { - clearRefreshInterval(this, !0), this.paused = !0 - }, ItemsRefresher.prototype.resume = function(options) { - this.paused = !1; - var refreshIntervalEndTime = this.refreshIntervalEndTime; - if (refreshIntervalEndTime) { - var remainingMs = refreshIntervalEndTime - (new Date).getTime(); - remainingMs > 0 && !this.needsRefresh ? resetRefreshInterval(this, remainingMs) : (this.needsRefresh = !0, this.refreshIntervalEndTime = null) + + resetRefreshInterval(this); + + if (this.afterRefresh) { + this.afterRefresh(result); } - return this.needsRefresh || options && options.refresh ? this.refreshItems() : Promise.resolve() - }, ItemsRefresher.prototype.refreshItems = function() { - return this.fetchData ? this.paused ? (this.needsRefresh = !0, Promise.resolve()) : (this.needsRefresh = !1, this.fetchData().then(onDataFetched.bind(this))) : Promise.resolve() - }, ItemsRefresher.prototype.notifyRefreshNeeded = function(isInForeground) { - if (this.paused) return void(this.needsRefresh = !0); - var timeout = this.refreshTimeout; - timeout && clearTimeout(timeout), !0 === isInForeground ? this.refreshItems() : this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 1e4) - }, ItemsRefresher.prototype.destroy = function() { - clearRefreshInterval(this), removeNotificationEvent(this, "UserDataChanged"), removeNotificationEvent(this, "TimerCreated"), removeNotificationEvent(this, "SeriesTimerCreated"), removeNotificationEvent(this, "TimerCancelled"), removeNotificationEvent(this, "SeriesTimerCancelled"), removeNotificationEvent(this, "LibraryChanged"), removeNotificationEvent(this, "playbackstop", playbackManager), this.fetchData = null, this.options = null - }, ItemsRefresher + } + + ItemsRefresher.prototype.destroy = function () { + + clearRefreshInterval(this); + + removeNotificationEvent(this, 'UserDataChanged'); + removeNotificationEvent(this, 'TimerCreated'); + removeNotificationEvent(this, 'SeriesTimerCreated'); + removeNotificationEvent(this, 'TimerCancelled'); + removeNotificationEvent(this, 'SeriesTimerCancelled'); + removeNotificationEvent(this, 'LibraryChanged'); + removeNotificationEvent(this, 'playbackstop', playbackManager); + + this.fetchData = null; + this.options = null; + }; + + return ItemsRefresher; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/layoutmanager.js b/src/bower_components/emby-webcomponents/layoutmanager.js index ae33babaa6..1059bf5758 100644 --- a/src/bower_components/emby-webcomponents/layoutmanager.js +++ b/src/bower_components/emby-webcomponents/layoutmanager.js @@ -1,19 +1,67 @@ -define(["browser", "appSettings", "events"], function(browser, appSettings, events) { - "use strict"; +define(['browser', 'appSettings', 'events'], function (browser, appSettings, events) { + 'use strict'; function setLayout(instance, layout, selectedLayout) { - layout === selectedLayout ? (instance[layout] = !0, document.documentElement.classList.add("layout-" + layout)) : (instance[layout] = !1, document.documentElement.classList.remove("layout-" + layout)) + + if (layout === selectedLayout) { + instance[layout] = true; + document.documentElement.classList.add('layout-' + layout); + } else { + instance[layout] = false; + document.documentElement.classList.remove('layout-' + layout); + } } - function LayoutManager() {} - return LayoutManager.prototype.setLayout = function(layout, save) { - layout && "auto" !== layout ? (setLayout(this, "mobile", layout), setLayout(this, "tv", layout), setLayout(this, "desktop", layout), !1 !== save && appSettings.set("layout", layout)) : (this.autoLayout(), !1 !== save && appSettings.set("layout", "")), events.trigger(this, "modechange") - }, LayoutManager.prototype.getSavedLayout = function(layout) { - return appSettings.get("layout") - }, LayoutManager.prototype.autoLayout = function() { - browser.mobile ? this.setLayout("mobile", !1) : browser.tv || browser.xboxOne ? this.setLayout("tv", !1) : this.setLayout(this.defaultLayout || "tv", !1) - }, LayoutManager.prototype.init = function() { + function LayoutManager() { + + } + + LayoutManager.prototype.setLayout = function (layout, save) { + + if (!layout || layout === 'auto') { + this.autoLayout(); + + if (save !== false) { + appSettings.set('layout', ''); + } + } else { + setLayout(this, 'mobile', layout); + setLayout(this, 'tv', layout); + setLayout(this, 'desktop', layout); + + if (save !== false) { + appSettings.set('layout', layout); + } + } + + events.trigger(this, 'modechange'); + }; + + LayoutManager.prototype.getSavedLayout = function (layout) { + + return appSettings.get('layout'); + }; + + LayoutManager.prototype.autoLayout = function () { + + // Take a guess at initial layout. The consuming app can override + if (browser.mobile) { + this.setLayout('mobile', false); + } else if (browser.tv || browser.xboxOne) { + this.setLayout('tv', false); + } else { + this.setLayout(this.defaultLayout || 'tv', false); + } + }; + + LayoutManager.prototype.init = function () { var saved = this.getSavedLayout(); - saved ? this.setLayout(saved, !1) : this.autoLayout() - }, new LayoutManager + if (saved) { + this.setLayout(saved, false); + } else { + this.autoLayout(); + } + }; + + return new LayoutManager(); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/lazyloader/lazyedgehack.css b/src/bower_components/emby-webcomponents/lazyloader/lazyedgehack.css index ca435a074d..e0fea48c40 100644 --- a/src/bower_components/emby-webcomponents/lazyloader/lazyedgehack.css +++ b/src/bower_components/emby-webcomponents/lazyloader/lazyedgehack.css @@ -1,4 +1,5 @@ .lazy { + /* In edge, intersection observer will not fire on 0px sized elements */ min-width: .1em; - min-height: .1em -} \ No newline at end of file + min-height: .1em; +} diff --git a/src/bower_components/emby-webcomponents/lazyloader/lazyloader-intersectionobserver.js b/src/bower_components/emby-webcomponents/lazyloader/lazyloader-intersectionobserver.js index df4a2e12a2..261ca84261 100644 --- a/src/bower_components/emby-webcomponents/lazyloader/lazyloader-intersectionobserver.js +++ b/src/bower_components/emby-webcomponents/lazyloader/lazyloader-intersectionobserver.js @@ -1,45 +1,103 @@ -define(["require", "browser"], function(require, browser) { - "use strict"; +define(['require', 'browser'], function (require, browser) { + 'use strict'; function LazyLoader(options) { - this.options = options + + this.options = options; } - function unveilElements(elements, root, callback) { - if (elements.length) { - new LazyLoader({ - callback: callback - }).addElements(elements) - } + if (browser.edge) { + require(['css!./lazyedgehack']); } - return browser.edge && require(["css!./lazyedgehack"]), LazyLoader.prototype.createObserver = function() { - var observerOptions = {}, - options = this.options, - loadedCount = 0, - callback = options.callback; + + LazyLoader.prototype.createObserver = function () { + + var observerOptions = {}; + var options = this.options; + var loadedCount = 0; + var callback = options.callback; + observerOptions.rootMargin = "50%"; - var observerId = "obs" + (new Date).getTime(), - self = this, - observer = new IntersectionObserver(function(entries) { - for (var j = 0, length2 = entries.length; j < length2; j++) { - var entry = entries[j]; - if (entry.intersectionRatio > 0) { - var target = entry.target; - observer.unobserve(target), target[observerId] || (target[observerId] = 1, callback(target), ++loadedCount >= self.elementCount && self.destroyObserver()) + + 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]; + + if (entry.intersectionRatio > 0) { + + // Stop watching and load the image + 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) { + } + }, + observerOptions + ); + + this.observer = observer; + }; + + LazyLoader.prototype.addElements = function (elements) { + var observer = this.observer; - 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) { + + 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; - observer && (observer.disconnect(), this.observer = null) - }, LazyLoader.prototype.destroy = function(elements) { - this.destroyObserver(), this.options = null - }, LazyLoader.lazyChildren = function(elem, callback) { - unveilElements(elem.getElementsByClassName("lazy"), elem, callback) - }, LazyLoader + + 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; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js b/src/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js index bab5cff978..318f6dbea0 100644 --- a/src/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js +++ b/src/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js @@ -1,103 +1,189 @@ -define(["visibleinviewport", "dom", "browser"], function(visibleinviewport, dom, browser) { - "use strict"; +define(['visibleinviewport', 'dom', 'browser'], function (visibleinviewport, dom, browser) { + 'use strict'; + + var thresholdX; + var thresholdY; + + var requestIdleCallback = window.requestIdleCallback || function (fn) { + fn(); + }; function resetThresholds() { - thresholdX = .3 * screen.availWidth, thresholdY = .3 * screen.availHeight + + var threshold = 0.3; + + thresholdX = screen.availWidth * threshold; + thresholdY = screen.availHeight * threshold; } function resetThresholdsOnTimer() { - setTimeout(resetThresholds, 500) + + setTimeout(resetThresholds, 500); } + if (browser.iOS) { + dom.addEventListener(window, "orientationchange", resetThresholdsOnTimer, { passive: true }); + dom.addEventListener(window, 'resize', resetThresholdsOnTimer, { passive: true }); + } else { + dom.addEventListener(window, "orientationchange", resetThresholds, { passive: true }); + dom.addEventListener(window, 'resize', resetThresholds, { passive: true }); + } + resetThresholds(); + function isVisible(elem) { - return visibleinviewport(elem, !0, thresholdX, thresholdY) + 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] = !0 + 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) { - for (var anyFound = !1, out = !1, elements = instance.elements, i = 0, length = elements.length; i < length; i++) { - if (cancellationTokens[tokenIndex]) return; - if (!unveiledElements[i]) { - var elem = elements[i]; - !out && isVisible(elem) ? (anyFound = !0, unveiledElements[i] = !0, callback(elem), loadedCount++) : anyFound && (out = !0) + + 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; + } } } - loadedCount >= elements.length && (dom.removeEventListener(document, "focus", unveil, { - capture: !0, - passive: !0 - }), dom.removeEventListener(document, "scroll", unveil, { - capture: !0, - passive: !0 - }), dom.removeEventListener(document, wheelEvent, unveil, { - capture: !0, - passive: !0 - }), dom.removeEventListener(window, "resize", unveil, { - capture: !0, - passive: !0 - })) + + 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) + cancellationTokens.length++; + + setTimeout(function () { + unveilInternal(index); + }, 1); } - var unveiledElements = [], - cancellationTokens = [], - loadedCount = 0; - dom.addEventListener(document, "focus", unveil, { - capture: !0, - passive: !0 - }), dom.addEventListener(document, "scroll", unveil, { - capture: !0, - passive: !0 - }), dom.addEventListener(document, wheelEvent, unveil, { - capture: !0, - passive: !0 - }), dom.addEventListener(window, "resize", unveil, { - capture: !0, - passive: !0 - }), unveil() + + 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 + + this.options = options; } - function unveilElements(elements, root, callback) { - if (elements.length) { - new LazyLoader({ - callback: callback - }).addElements(elements) - } - } - var thresholdX, thresholdY; - window.requestIdleCallback; - browser.iOS ? (dom.addEventListener(window, "orientationchange", resetThresholdsOnTimer, { - passive: !0 - }), dom.addEventListener(window, "resize", resetThresholdsOnTimer, { - passive: !0 - })) : (dom.addEventListener(window, "orientationchange", resetThresholds, { - passive: !0 - }), dom.addEventListener(window, "resize", resetThresholds, { - passive: !0 - })), resetThresholds(); - var wheelEvent = document.implementation.hasFeature("Event.wheel", "3.0") ? "wheel" : "mousewheel"; - return LazyLoader.prototype.createObserver = function() { - unveilElementsInternal(this, this.options.callback), this.observer = 1 - }, LazyLoader.prototype.addElements = function(elements) { + 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]); - this.observer || this.createObserver() - }, LazyLoader.prototype.destroyObserver = function(elements) {}, LazyLoader.prototype.destroy = function(elements) { - this.destroyObserver(), this.options = null - }, LazyLoader.lazyChildren = function(elem, callback) { - unveilElements(elem.getElementsByClassName("lazy"), elem, callback) - }, LazyLoader + + 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; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/listview/listview.css b/src/bower_components/emby-webcomponents/listview/listview.css index ac9afc6e13..e31148286f 100644 --- a/src/bower_components/emby-webcomponents/listview/listview.css +++ b/src/bower_components/emby-webcomponents/listview/listview.css @@ -1,130 +1,97 @@ -.listItem-withContentWrapper, -.listItemBody { - -webkit-box-orient: vertical; - -webkit-box-direction: normal -} - -.listItemBody, -.listItemBodyText { - overflow: hidden; - -o-text-overflow: ellipsis; - text-overflow: ellipsis -} - .listItem { - background: 0 0; + background: transparent; border: 0; - outline: 0 !important; + outline: none !important; color: inherit; vertical-align: middle; font-family: inherit; font-size: inherit; margin: 0; - -webkit-box-align: center; - -webkit-align-items: center; + display: block; align-items: center; text-align: left; padding: .25em .25em .25em .5em; cursor: pointer; - overflow: hidden + overflow: hidden; } .listItem-withContentWrapper { - -webkit-flex-direction: column; flex-direction: column; - -webkit-box-align: start; - -webkit-align-items: flex-start; - align-items: flex-start + align-items: flex-start; } .listItem[data-action=none] { - cursor: default + cursor: default; } .listItem-content { - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - width: 100% -} - -.listItemBody, -.listItemButton, -.listItemIcon, -.listItemImage { - display: inline-block; - vertical-align: middle + width: 100%; } .listItem-button { - width: 100% + width: 100%; } .listItem-indexnumberleft { - margin-right: 1em + margin-right: 1em; } .listItem-border { border-bottom-width: .1em; - border-bottom-style: solid + border-bottom-style: solid; } -.listItemAside, -.listItemIcon, -.listItemImage { - -webkit-flex-shrink: 0; - flex-shrink: 0 +.listItemImage, .listItemIcon, .listItemAside { + flex-shrink: 0; +} + +.listItemBody, .listItemImage, .listItemIcon { + display: inline-block; + vertical-align: middle; } .listItemButton { margin: 0; - -webkit-flex-shrink: 0; + display: inline-block; + vertical-align: middle; flex-shrink: 0; - contain: layout style -} - -.listItemImage, -.listItemImageButton { - display: -webkit-box; - display: -webkit-flex + contain: layout style; } .listViewDragHandle { margin-left: -.25em !important; - touch-action: none + touch-action: none; } .listItemBody { - -webkit-box-flex: 1; - -webkit-flex-grow: 1; flex-grow: 1; padding: .85em .75em; - -webkit-flex-direction: column; + overflow: hidden; + text-overflow: ellipsis; flex-direction: column; vertical-align: middle; - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center + justify-content: center; } .layout-tv .listItemBody { - padding: .35em .75em + padding: .35em .75em; } .listItemBody-noleftpadding { - padding-left: 0 !important + padding-left: 0 !important; } .listItemBodyText { margin: 0; - padding: .1em 0 + padding: .1em 0; + overflow: hidden; + text-overflow: ellipsis; } .listItemBodyText-nowrap { - white-space: nowrap + white-space: nowrap; } .listItemImage { @@ -133,189 +100,164 @@ min-width: 2.78em; min-height: 2.78em; background-repeat: no-repeat; - -webkit-background-size: contain; background-size: contain; - -webkit-flex-shrink: 0; flex-shrink: 0; background-position: center center; position: relative; - display: flex + display: flex; } .listItemImage-large { width: 19.5vw; height: 13vw; background-position: center center; - margin-right: .75em + margin-right: .75em; } .listItemImageButton { - -webkit-align-self: center; align-self: center; justify-self: center; margin: auto; color: rgba(255, 255, 255, .6); font-size: 1.6em; - background: 0 0; - -webkit-transition: -webkit-transform .2s ease-out; - -o-transition: transform .2s ease-out; - transition: transform .2s ease-out; - display: flex + background: transparent; + transition: transform 200ms ease-out; + display: flex; } -.listItemImageButton:hover { - -webkit-transform: scale(1.2, 1.2); - transform: scale(1.2, 1.2) -} + .listItemImageButton:hover { + transform: scale(1.2, 1.2); + } .listItemImageButton-icon { - background: rgba(0, 0, 0, .4); + background: rgba(0,0,0,.4); border: .08em solid currentColor; - -webkit-border-radius: 100em; border-radius: 100em; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - padding: .21em + padding: .21em; } -@media all and (max-width:64em) { +@media all and (max-width: 64em) { + .listItemImage-large { width: 33.75vw; height: 22.5vw; - margin-right: 0 !important + margin-right: 0 !important; } .listItemImageButton { - font-size: 1.02em !important + font-size: 1.02em !important; } .listItemBody { - padding-left: .75em + padding-left: .75em; } } -@media all and (max-width:50em) { +@media all and (max-width: 50em) { + .listItemBody { - padding-right: .5em + padding-right: .5em; } } .listItemImage-large-tv { width: 30vw !important; - height: 20vw !important + height: 20vw !important; } .listItemIcon { width: 1em !important; height: 1em !important; font-size: 143%; - padding: 0 .25em 0 0 + padding: 0 .25em 0 0; } -.listItemIcon:not(.listItemIcon-transparent) { - background-color: #00a4dc; - color: #fff; - padding: .5em; - -webkit-border-radius: 100em; - border-radius: 100em; - margin: 0 .2em 0 .4em -} + .listItemIcon:not(.listItemIcon-transparent) { + background-color: #52B54B; + color: #fff; + padding: .5em; + border-radius: 100em; + margin: 0 .2em 0 .4em; + } .listItemProgressBar { position: absolute; bottom: 0; left: 0; - right: 0 + right: 0; } .listItem:focus { - -webkit-border-radius: .2em; - border-radius: .2em + border-radius: .2em; } -.listItem:focus .secondary { - color: inherit !important -} + .listItem:focus .secondary { + color: inherit !important; + } .listItem-focusscale { - -webkit-transition: -webkit-transform .2s ease-out; - -o-transition: transform .2s ease-out; - transition: transform .2s ease-out + transition: transform .2s ease-out; } -.listItem-focusscale:focus { - -webkit-transform: scale(1.025, 1.025); - transform: scale(1.025, 1.025) -} + .listItem-focusscale:focus { + transform: scale(1.025, 1.025); + } .paperList { - margin: .5em auto + margin: .5em auto; } .paperList-clear { - background-color: transparent !important + background-color: transparent !important; } .listItemMediaInfo { - -webkit-box-align: center; - -webkit-align-items: center; + /* Don't display if flex not supported */ + display: none; align-items: center; - margin-right: 1em + margin-right: 1em; } .listGroupHeader-first { - margin-top: 0 + margin-top: 0; } .listItemIndicators { right: .324em; top: .324em; position: absolute; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; - align-items: center + align-items: center; } -.listItem, -.listItemBody, -.listItemMediaInfo { - display: -webkit-box; - display: -webkit-flex; +.listItem, .listItemBody, .listItemMediaInfo { display: flex; - contain: layout style + contain: layout style; } .listItem-bottomoverview { font-size: 88%; margin-bottom: 1em; - margin-top: .2em + margin-top: .2em; } -@media all and (max-width:50em) { +@media all and (max-width: 50em) { - .listItem .criticRating, - .listItem .endsAt, - .listItem-overview { - display: none !important + .listItem .endsAt, .listItem .criticRating, .listItem-overview { + display: none !important; } } -@media all and (min-width:50em) { +@media all and (min-width: 50em) { + .listItem-bottomoverview { - display: none !important + display: none !important; } } .listItemCheckboxContainer { - width: auto !important -} \ No newline at end of file + width: auto !important; +} diff --git a/src/bower_components/emby-webcomponents/listview/listview.js b/src/bower_components/emby-webcomponents/listview/listview.js index be183c9978..4f4a0a91eb 100644 --- a/src/bower_components/emby-webcomponents/listview/listview.js +++ b/src/bower_components/emby-webcomponents/listview/listview.js @@ -1,131 +1,543 @@ -define(["itemHelper", "mediaInfo", "indicators", "connectionManager", "layoutManager", "globalize", "datetime", "apphost", "css!./listview", "emby-ratingbutton", "emby-playstatebutton"], function(itemHelper, mediaInfo, indicators, connectionManager, layoutManager, globalize, datetime, appHost) { - "use strict"; +define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutManager', 'globalize', 'datetime', 'apphost', 'css!./listview', 'emby-ratingbutton', 'emby-playstatebutton'], function (itemHelper, mediaInfo, indicators, connectionManager, layoutManager, globalize, datetime, appHost) { + 'use strict'; function getIndex(item, options) { - if ("disc" === options.index) return null == item.ParentIndexNumber ? "" : globalize.translate("sharedcomponents#ValueDiscNumber", item.ParentIndexNumber); - var code, name, sortBy = (options.sortBy || "").toLowerCase(); - return 0 === sortBy.indexOf("sortname") ? "Episode" === item.Type ? "" : (name = (item.SortName || item.Name || "?")[0].toUpperCase(), code = name.charCodeAt(0), code < 65 || code > 90 ? "#" : name.toUpperCase()) : 0 === sortBy.indexOf("officialrating") ? item.OfficialRating || globalize.translate("sharedcomponents#Unrated") : 0 === sortBy.indexOf("communityrating") ? null == item.CommunityRating ? globalize.translate("sharedcomponents#Unrated") : Math.floor(item.CommunityRating) : 0 === sortBy.indexOf("criticrating") ? null == item.CriticRating ? globalize.translate("sharedcomponents#Unrated") : Math.floor(item.CriticRating) : 0 === sortBy.indexOf("albumartist") && item.AlbumArtist ? (name = item.AlbumArtist[0].toUpperCase(), code = name.charCodeAt(0), code < 65 || code > 90 ? "#" : name.toUpperCase()) : "" + + if (options.index === 'disc') { + + return item.ParentIndexNumber == null ? '' : globalize.translate('sharedcomponents#ValueDiscNumber', item.ParentIndexNumber); + } + + var sortBy = (options.sortBy || '').toLowerCase(); + var code, name; + + if (sortBy.indexOf('sortname') === 0) { + + if (item.Type === 'Episode') { + return ''; + } + + // SortName + name = (item.SortName || item.Name || '?')[0].toUpperCase(); + + code = name.charCodeAt(0); + if (code < 65 || code > 90) { + return '#'; + } + + return name.toUpperCase(); + } + if (sortBy.indexOf('officialrating') === 0) { + + return item.OfficialRating || globalize.translate('sharedcomponents#Unrated'); + } + if (sortBy.indexOf('communityrating') === 0) { + + if (item.CommunityRating == null) { + return globalize.translate('sharedcomponents#Unrated'); + } + + return Math.floor(item.CommunityRating); + } + if (sortBy.indexOf('criticrating') === 0) { + + if (item.CriticRating == null) { + return globalize.translate('sharedcomponents#Unrated'); + } + + return Math.floor(item.CriticRating); + } + if (sortBy.indexOf('albumartist') === 0) { + + // SortName + if (!item.AlbumArtist) { + return ''; + } + + name = item.AlbumArtist[0].toUpperCase(); + + code = name.charCodeAt(0); + if (code < 65 || code > 90) { + return '#'; + } + + return name.toUpperCase(); + } + return ''; } function getImageUrl(item, width) { - var apiClient = connectionManager.getApiClient(item.ServerId), - options = { - width: width, - type: "Primary" - }; - return item.ImageTags && item.ImageTags.Primary ? (options.tag = item.ImageTags.Primary, apiClient.getScaledImageUrl(item.Id, options)) : item.AlbumId && item.AlbumPrimaryImageTag ? (options.tag = item.AlbumPrimaryImageTag, apiClient.getScaledImageUrl(item.AlbumId, options)) : item.SeriesId && item.SeriesPrimaryImageTag ? (options.tag = item.SeriesPrimaryImageTag, apiClient.getScaledImageUrl(item.SeriesId, options)) : item.ParentPrimaryImageTag ? (options.tag = item.ParentPrimaryImageTag, apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, options)) : null + + var apiClient = connectionManager.getApiClient(item.ServerId); + + var options = { + width: width, + type: "Primary" + }; + + if (item.ImageTags && item.ImageTags.Primary) { + + options.tag = item.ImageTags.Primary; + return apiClient.getScaledImageUrl(item.Id, options); + } + + if (item.AlbumId && item.AlbumPrimaryImageTag) { + + options.tag = item.AlbumPrimaryImageTag; + return apiClient.getScaledImageUrl(item.AlbumId, options); + } + + else if (item.SeriesId && item.SeriesPrimaryImageTag) { + + options.tag = item.SeriesPrimaryImageTag; + return apiClient.getScaledImageUrl(item.SeriesId, options); + + } + else if (item.ParentPrimaryImageTag) { + + options.tag = item.ParentPrimaryImageTag; + return apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, options); + } + + return null; } function getChannelImageUrl(item, width) { - var apiClient = connectionManager.getApiClient(item.ServerId), - options = { - width: width, - type: "Primary" - }; - return item.ChannelId && item.ChannelPrimaryImageTag ? (options.tag = item.ChannelPrimaryImageTag, apiClient.getScaledImageUrl(item.ChannelId, options)) : null + + var apiClient = connectionManager.getApiClient(item.ServerId); + + var options = { + width: width, + type: "Primary" + }; + + if (item.ChannelId && item.ChannelPrimaryImageTag) { + + options.tag = item.ChannelPrimaryImageTag; + return apiClient.getScaledImageUrl(item.ChannelId, options); + } + + return null; } function getTextLinesHtml(textlines, isLargeStyle) { - for (var html = "", largeTitleTagName = layoutManager.tv ? "h2" : "div", i = 0, length = textlines.length; i < length; i++) { - textlines[i] && (html += 0 === i ? isLargeStyle ? "<" + largeTitleTagName + ' class="listItemBodyText">' : '
' : '
', html += textlines[i] || " ", html += 0 === i && isLargeStyle ? "" : "
") + + var html = ''; + + var largeTitleTagName = layoutManager.tv ? 'h2' : 'div'; + + for (var i = 0, length = textlines.length; i < length; i++) { + + var text = textlines[i]; + + if (!text) { + continue; + } + + if (i === 0) { + if (isLargeStyle) { + html += '<' + largeTitleTagName + ' class="listItemBodyText">'; + } else { + html += '
'; + } + } else { + html += '
'; + } + html += (textlines[i] || ' '); + if (i === 0 && isLargeStyle) { + html += ''; + } else { + html += '
'; + } } - return html + + return html; } function getRightButtonsHtml(options) { - for (var html = "", i = 0, length = options.rightButtons.length; i < length; i++) { + + var html = ''; + + for (var i = 0, length = options.rightButtons.length; i < length; i++) { + var button = options.rightButtons[i]; - html += '" + + html += ''; } - return html + + return html; } function getId(item) { - return item.Id + return item.Id; } function getListViewHtml(options) { - for (var items = options.items, groupTitle = "", action = options.action || "link", isLargeStyle = "large" === options.imageSize, enableOverview = options.enableOverview, clickEntireItem = !!layoutManager.tv, outerTagName = clickEntireItem ? "button" : "div", enableSideMediaInfo = null == options.enableSideMediaInfo || options.enableSideMediaInfo, outerHtml = "", enableContentWrapper = options.enableOverview && !layoutManager.tv, containerAlbumArtistIds = (options.containerAlbumArtists || []).map(getId), i = 0, length = items.length; i < length; i++) { - var item = items[i], - html = ""; + + var items = options.items; + + var groupTitle = ''; + var action = options.action || 'link'; + + var isLargeStyle = options.imageSize === 'large'; + var enableOverview = options.enableOverview; + + var clickEntireItem = layoutManager.tv ? true : false; + var outerTagName = clickEntireItem ? 'button' : 'div'; + var enableSideMediaInfo = options.enableSideMediaInfo != null ? options.enableSideMediaInfo : true; + + var outerHtml = ''; + + var enableContentWrapper = options.enableOverview && !layoutManager.tv; + var containerAlbumArtistIds = (options.containerAlbumArtists || []).map(getId); + + for (var i = 0, length = items.length; i < length; i++) { + + var item = items[i]; + + var html = ''; + if (options.showIndex) { + var itemGroupTitle = getIndex(item, options); - itemGroupTitle !== groupTitle && (html && (html += "
"), html += 0 === i ? '

' : '

', html += itemGroupTitle, html += "

", html += "
", groupTitle = itemGroupTitle) + + if (itemGroupTitle !== groupTitle) { + + if (html) { + html += '
'; + } + + if (i === 0) { + html += '

'; + } + else { + html += '

'; + } + html += itemGroupTitle; + html += '

'; + + html += '
'; + + groupTitle = itemGroupTitle; + } } + var cssClass = "listItem"; - (options.border || !1 !== options.highlight && !layoutManager.tv) && (cssClass += " listItem-border"), clickEntireItem && (cssClass += " itemAction listItem-button"), layoutManager.tv && (cssClass += " listItem-focusscale"); - var downloadWidth = 80; - isLargeStyle && (cssClass += " listItem-largeImage", downloadWidth = 500); - var playlistItemId = item.PlaylistItemId ? ' data-playlistitemid="' + item.PlaylistItemId + '"' : "", - positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? ' data-positionticks="' + item.UserData.PlaybackPositionTicks + '"' : "", - collectionIdData = options.collectionId ? ' data-collectionid="' + options.collectionId + '"' : "", - playlistIdData = options.playlistId ? ' data-playlistid="' + options.playlistId + '"' : "", - mediaTypeData = item.MediaType ? ' data-mediatype="' + item.MediaType + '"' : "", - collectionTypeData = item.CollectionType ? ' data-collectiontype="' + item.CollectionType + '"' : "", - channelIdData = item.ChannelId ? ' data-channelid="' + item.ChannelId + '"' : ""; - if (enableContentWrapper && (cssClass += " listItem-withContentWrapper"), html += "<" + outerTagName + ' class="' + cssClass + '"' + playlistItemId + ' data-action="' + action + '" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + ">", enableContentWrapper && (html += '
'), !clickEntireItem && options.dragHandle && (html += ''), !1 !== options.image) { - var imgUrl = "channel" === options.imageSource ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth); - console.log(imgUrl); - var imageClass = isLargeStyle ? "listItemImage listItemImage-large" : "listItemImage"; - isLargeStyle && layoutManager.tv && (imageClass += " listItemImage-large-tv"); - var playOnImageClick = options.imagePlayButton && !layoutManager.tv; - clickEntireItem || (imageClass += " itemAction"); - var imageAction = playOnImageClick ? "resume" : action; - html += imgUrl ? '
' : '
'; - var indicatorsHtml = ""; - indicatorsHtml += indicators.getPlayedIndicatorHtml(item), indicatorsHtml && (html += '
' + indicatorsHtml + "
"), playOnImageClick && (html += ''); - var progressHtml = indicators.getProgressBarHtml(item, { - containerClass: "listItemProgressBar" - }); - progressHtml && (html += progressHtml), html += "
" + + if (options.border || (options.highlight !== false && !layoutManager.tv)) { + cssClass += ' listItem-border'; } - options.showIndexNumberLeft && (html += '
', html += item.IndexNumber || " ", html += "
"); + + if (clickEntireItem) { + cssClass += ' itemAction listItem-button'; + } + + if (layoutManager.tv) { + cssClass += ' listItem-focusscale'; + } + + var downloadWidth = 80; + + if (isLargeStyle) { + cssClass += " listItem-largeImage"; + downloadWidth = 500; + } + + var playlistItemId = item.PlaylistItemId ? (' data-playlistitemid="' + item.PlaylistItemId + '"') : ''; + + var positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? (' data-positionticks="' + item.UserData.PlaybackPositionTicks + '"') : ''; + var collectionIdData = options.collectionId ? (' data-collectionid="' + options.collectionId + '"') : ''; + var playlistIdData = options.playlistId ? (' data-playlistid="' + options.playlistId + '"') : ''; + var mediaTypeData = item.MediaType ? (' data-mediatype="' + item.MediaType + '"') : ''; + var collectionTypeData = item.CollectionType ? (' data-collectiontype="' + item.CollectionType + '"') : ''; + var channelIdData = item.ChannelId ? (' data-channelid="' + item.ChannelId + '"') : ''; + + if (enableContentWrapper) { + + cssClass += ' listItem-withContentWrapper'; + } + + html += '<' + outerTagName + ' class="' + cssClass + '"' + playlistItemId + ' data-action="' + action + '" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + '>'; + + if (enableContentWrapper) { + + html += '
'; + } + + if (!clickEntireItem && options.dragHandle) { + //html += ''; + // Firefox and Edge are not allowing the button to be draggable + html += ''; + } + + if (options.image !== false) { + var imgUrl = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth); + console.log(imgUrl); + var imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage'; + + if (isLargeStyle && layoutManager.tv) { + imageClass += ' listItemImage-large-tv'; + } + + var playOnImageClick = options.imagePlayButton && !layoutManager.tv; + + if (!clickEntireItem) { + imageClass += ' itemAction'; + } + + var imageAction = playOnImageClick ? 'resume' : action; + + if (imgUrl) { + html += '
'; + } else { + html += '
'; + } + + var indicatorsHtml = ''; + indicatorsHtml += indicators.getPlayedIndicatorHtml(item); + + if (indicatorsHtml) { + html += '
' + indicatorsHtml + '
'; + } + + if (playOnImageClick) { + html += ''; + } + + var progressHtml = indicators.getProgressBarHtml(item, { + containerClass: 'listItemProgressBar' + }); + + if (progressHtml) { + html += progressHtml; + } + html += '
'; + } + + if (options.showIndexNumberLeft) { + + html += '
'; + html += (item.IndexNumber || ' '); + html += '
'; + } + var textlines = []; - options.showProgramDateTime && textlines.push(datetime.toLocaleString(datetime.parseISO8601Date(item.StartDate), { - weekday: "long", - month: "short", - day: "numeric", - hour: "numeric", - minute: "2-digit" - })), options.showProgramTime && textlines.push(datetime.getDisplayTime(datetime.parseISO8601Date(item.StartDate))), options.showChannel && item.ChannelName && textlines.push(item.ChannelName); + + if (options.showProgramDateTime) { + textlines.push(datetime.toLocaleString(datetime.parseISO8601Date(item.StartDate), { + + weekday: 'long', + month: 'short', + day: 'numeric', + hour: 'numeric', + minute: '2-digit' + })); + } + + if (options.showProgramTime) { + textlines.push(datetime.getDisplayTime(datetime.parseISO8601Date(item.StartDate))); + } + + if (options.showChannel) { + if (item.ChannelName) { + textlines.push(item.ChannelName); + } + } + var parentTitle = null; - options.showParentTitle && ("Episode" === item.Type ? parentTitle = item.SeriesName : (item.IsSeries || item.EpisodeTitle && item.Name) && (parentTitle = item.Name)); + + if (options.showParentTitle) { + if (item.Type === 'Episode') { + parentTitle = item.SeriesName; + } + + else if (item.IsSeries || (item.EpisodeTitle && item.Name)) { + parentTitle = item.Name; + } + } + var displayName = itemHelper.getDisplayName(item, { includeParentInfo: options.includeParentInfoInTitle }); - if (options.showIndexNumber && null != item.IndexNumber && (displayName = item.IndexNumber + ". " + displayName), options.showParentTitle && options.parentTitleWithTitle ? (displayName && (parentTitle && (parentTitle += " - "), parentTitle = (parentTitle || "") + displayName), textlines.push(parentTitle || "")) : options.showParentTitle && textlines.push(parentTitle || ""), displayName && !options.parentTitleWithTitle && textlines.push(displayName), item.IsFolder) !1 !== options.artist && item.AlbumArtist && "MusicAlbum" === item.Type && textlines.push(item.AlbumArtist); - else { - var showArtist = !0 === options.artist, - artistItems = item.ArtistItems; - showArtist || !1 === options.artist || (artistItems && artistItems.length ? (artistItems.length > 1 || -1 === containerAlbumArtistIds.indexOf(artistItems[0].Id)) && (showArtist = !0) : showArtist = !0), showArtist && artistItems && "MusicAlbum" !== item.Type && textlines.push(artistItems.map(function(a) { - return a.Name - }).join(", ")) + + if (options.showIndexNumber && item.IndexNumber != null) { + displayName = item.IndexNumber + ". " + displayName; } - "Game" === item.Type && textlines.push(item.GameSystem), "TvChannel" === item.Type && item.CurrentProgram && textlines.push(itemHelper.getDisplayName(item.CurrentProgram)), cssClass = "listItemBody", clickEntireItem || (cssClass += " itemAction"), !1 === options.image && (cssClass += " listItemBody-noleftpadding"), html += '
'; - if (html += getTextLinesHtml(textlines, isLargeStyle), !1 !== options.mediaInfo && !enableSideMediaInfo) { - html += '
' + mediaInfo.getPrimaryMediaInfoHtml(item, { - episodeTitle: !1, - originalAirDate: !1, - subtitles: !1 - }) + "
" + + if (options.showParentTitle && options.parentTitleWithTitle) { + + if (displayName) { + + if (parentTitle) { + parentTitle += ' - '; + } + parentTitle = (parentTitle || '') + displayName; + } + + textlines.push(parentTitle || ''); } - if (enableOverview && item.Overview && (html += '
', html += item.Overview, html += "
"), html += "
", !1 !== options.mediaInfo && enableSideMediaInfo && (html += '
' + mediaInfo.getPrimaryMediaInfoHtml(item, { - year: !1, - container: !1, - episodeTitle: !1, - criticRating: !1, - endsAt: !1 - }) + "
"), options.recordButton || "Timer" !== item.Type && "Program" !== item.Type || (html += indicators.getTimerIndicator(item).replace("indicatorIcon", "indicatorIcon listItemAside")), !clickEntireItem && (options.addToListButton && (html += ''), !1 !== options.moreButton && (html += ''), options.infoButton && (html += ''), options.rightButtons && (html += getRightButtonsHtml(options)), !1 !== options.enableUserDataButtons)) { - html += ''; - var userData = item.UserData || {}, - likes = null == userData.Likes ? "" : userData.Likes; - itemHelper.canMarkPlayed(item) && (html += ''), itemHelper.canRate(item) && (html += ''), html += "" + else if (options.showParentTitle) { + textlines.push(parentTitle || ''); } - enableContentWrapper && (html += "
", enableOverview && item.Overview && (html += '
', html += item.Overview, html += "
")), html += "", outerHtml += html + + if (displayName && !options.parentTitleWithTitle) { + textlines.push(displayName); + } + + if (item.IsFolder) { + if (options.artist !== false) { + + if (item.AlbumArtist && item.Type === 'MusicAlbum') { + textlines.push(item.AlbumArtist); + } + } + } else { + + var showArtist = options.artist === true; + var artistItems = item.ArtistItems; + + if (!showArtist && options.artist !== false) { + + if (!artistItems || !artistItems.length) { + showArtist = true; + } + else if (artistItems.length > 1 || containerAlbumArtistIds.indexOf(artistItems[0].Id) === -1) { + showArtist = true; + } + } + + if (showArtist) { + + if (artistItems && item.Type !== 'MusicAlbum') { + textlines.push(artistItems.map(function (a) { + return a.Name; + }).join(', ')); + } + } + } + + if (item.Type === 'Game') { + textlines.push(item.GameSystem); + } + + if (item.Type === 'TvChannel') { + + if (item.CurrentProgram) { + textlines.push(itemHelper.getDisplayName(item.CurrentProgram)); + } + } + + cssClass = 'listItemBody'; + if (!clickEntireItem) { + cssClass += ' itemAction'; + } + + if (options.image === false) { + cssClass += ' listItemBody-noleftpadding'; + } + + html += '
'; + + var moreIcon = ''; + + html += getTextLinesHtml(textlines, isLargeStyle); + + if (options.mediaInfo !== false) { + if (!enableSideMediaInfo) { + + var mediaInfoClass = 'secondary listItemMediaInfo listItemBodyText'; + + html += '
' + mediaInfo.getPrimaryMediaInfoHtml(item, { + episodeTitle: false, + originalAirDate: false, + subtitles: false + + }) + '
'; + } + } + + if (enableOverview && item.Overview) { + html += '
'; + html += item.Overview; + html += '
'; + } + + html += '
'; + + if (options.mediaInfo !== false) { + if (enableSideMediaInfo) { + html += '
' + mediaInfo.getPrimaryMediaInfoHtml(item, { + + year: false, + container: false, + episodeTitle: false, + criticRating: false, + endsAt: false + + }) + '
'; + } + } + + if (!options.recordButton && (item.Type === 'Timer' || item.Type === 'Program')) { + html += indicators.getTimerIndicator(item).replace('indicatorIcon', 'indicatorIcon listItemAside'); + } + + if (!clickEntireItem) { + + if (options.addToListButton) { + html += ''; + } + + if (options.moreButton !== false) { + html += ''; + } + + if (options.infoButton) { + html += ''; + } + + if (options.rightButtons) { + html += getRightButtonsHtml(options); + } + + if (options.enableUserDataButtons !== false) { + + html += ''; + + var userData = item.UserData || {}; + var likes = userData.Likes == null ? '' : userData.Likes; + + if (itemHelper.canMarkPlayed(item)) { + html += ''; + } + + if (itemHelper.canRate(item)) { + html += ''; + } + + html += ''; + } + } + + if (enableContentWrapper) { + html += '
'; + + if (enableOverview && item.Overview) { + html += '
'; + html += item.Overview; + html += '
'; + } + } + + html += ''; + + outerHtml += html; } - return outerHtml + + return outerHtml; } + return { getListViewHtml: getListViewHtml - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/loading/loader2.gif b/src/bower_components/emby-webcomponents/loading/loader2.gif index 86fb6daa79669dabcdf43da630e5de612a44140e..79a5432fb576d35c429afa167e2ffe4ed981182f 100644 GIT binary patch literal 36058 zcmeF&RZv{r``~-58+X^>?rtHtyK8WF*FfXlXyfh#8VN29jk^U15;O@ANFWdbf#9L% z{ms9u@LqS0zk&TUw=jZ1L1Y%)f z;nSy2DF1yiA#rt8jE$5O^i_oU1<_Ie*<`xM0Q~34`=0~KAgP(odb2CUd4XVAe~zVi^{s`OdO+vpHn` zXTqiU>4h@ftj*U-DPEF6u z&do2pUtC)Lu<{NK0KiZ}+umON6upjtfsT53w6$}5^7+(j@9WXU<@b~8>$6+y?TufT ze}60fLBp9)yTF!=!6IEGooRbLnv62ZRth7s8&5@N@@Q_)L{?9yC{_V;fxz6^Ks3#0@%U%lhR)-~a&=r3@;S2CS~dC~m_EU}8cbsJ zYCMj_^FDPq**!Xc((Li9AvJbizAa!F*TH+=s4cH!$1m;Nx)?+ICb@*NoS_dfImXbrnC$sIs( z_ad%|OMNN=pZ%6G0aX)gDvDe@j46rQ0|tntj|gJ~e}aSo;@M2^m{OP;sQ}4*{b9^$ zTyw`55V37Z`V6WcFpR{P8Mn+(VjOpjOqGWj`fNdN>}7Wy=`fbu&l>mWIVRE;4Ed5C z4d|&hJz=bc&5&^P0_TVmhGO|fF7zVr;&8UoZ?pGkCBgk$=;iu9`q0wfd<YXf0#wDHP?JVt;v&qV69X4n2SXz3km0h4MHMNtKQy(aW_I5HBs~4 z<==5PyU*dEHgp$9aJ1Z=Y@@s#3<=|D>%*D%Xh*g@r<{e41 za`B>U=ZAas=Dfl6f$L;w`B;482l*tT6X~Nws5Y0lBJc)eUJqPZ+WR)&eQWyV`hj7MIpSL9X}Pa0M~JqyDz%H_<|SvWufuDJ8#~7 z3EZH(6IdtaM~h6xT`fIG<&fwRnN?&^^g{+~)f64ERp$3eUq%?^@PX(Eiuh{K=bSm9>-yqrt#KTl@==!GH7Y$x2P1;|nG{{ywt!)MQuGc73$oox3NMmT zGopC`=7l)@-`~6QYKd@lP%F8F!FiO1``iq?lh~eaN}Qm#39v#tort@Ht{Fix(ON9x zBEbT>IJ5*MYi5#Tv-IR07k9g9h2PYgU>YtF81_-?KUi$r+RLAr8iz@}7Z2YCHlF4pTNunre&HAhV+K`((2fjuISL zju=2l8(pYVAMq3~Y-F*Z`LbST_>4>#y?yavqQgXrhm5Pnq9**Is@$}rR-()u9AMa# zgYpjg>K3{Tl3S@%Ibf&1vp`n+Yi3o`TXHhc{Lt45xXxMT%~OuV`Vfs%ZA>HPs9`0# zf*L$m9Y_b$Kr*hlN9W4%*`TYU7QD}Mxvt2I<6?H6GnBjQQj`*_k-hg@y{ui!RujvL zkOnLQMNMQ*oX`z|ElhyQ-8DgX9&ZvF=gMw4n%pS2_G%gt1O;aAk*7xO** zr-G5_cchVGk#^%4@Ig0EK}=v&5r$gT*qfp@w?}25zXu$hE_xxc0O~N^d^bdR-bO`% zS4$$gD?f zfOv@45k6Is0E1~A7{Ei)zwU^O3^-KqSh zy?^N2{l7}wZ8DsNAG_gP^Z@TB#I6ZRH=g$2UpTuv?2YB4L#H-=xXX{+_n%SwOGx}} z^mZK$!{8<)49AJziE%K0*^Q%?w?zAT9(Ml79`sWDZg)DVemoeQ>Gxgi(X5@>4^AWZiM^rgFrlTYnhw`F8Pk=<)9_5aGZcrrzBc z?ehg#Z{UD(>26Bq`4XBraLA!|KWFv)yKrgXo5a%nV&wBxCE?()n%=`o$@4W#Z}5lN z(!)o@^PjfN!82FA$L*cx8~D=TdFayP=f~&U5yGL1WWA>YTIAi#ufa7Ys=NLjjKlCR zh^w08gcFIszvk;_cAf3sDDp2yb_^@&z=KV1=>9Fn&t%^>1<_)}F@eIM(2X}Q+M~rlptbtY#{!}wO!Viv zP-?6<(4J6|us0%Opx0&~R%HO|T~x$(5Cdwg_(kmJ`dHMvXuHr*{yXBo8))QUBHkGn z4$gp^n;7-_I0k!wA~?ox+I4~=p5H8<2PVf14p5niF@wfS><1aoD47r?QXB_q!`_%L z$8&rQvV)PxfYEJW$_g{yy*;rkY94K-UYwyxq(aQ)z(n;zK!CYC{{}l{70QG~VT+Qou;JZtoM?NIaybI|K9MX9Ot$=ZvQbbJJ zzE4WM69KZjcy+52zd1&4-X!dYX|jp~mn4bbnwxB4$+3l`)QhKI5~aUl%(#%xfY+vZ zDgZwff-_9h=G}njlkPvv3D#lg-^>YcBy}#}8P3ZYSg{#pYaBZ;mG@L`D18uj6&sh( zbT=rp77WGc18xAK@fv`CVVMEItZ_Iaxx4eiByhypnXV|+TR;24FY~2n_Dt|=h5W1| zMyM)E&S7OX*BU3)cs7k{4yry>XPHyjUFlC@w*N>Djj^354Y7n z$@BwdU&3unEePaJlxh=S$B7vvkXu<$zX~NXYY@v-cE?l=&rNgA)wBS(HRKhO7aS7h zqHN}+shAj%=TAE4M+oMbVe1C<$wfj6_Am+qW{njl)5{!kbOiH-wv4onFvTXd!S0zc zC`C>d+Qrl;z8a7+hk|^OLNRKrGHR3zE{TG^qSz6!_OAT5)P_0OCM_CRO%?^{7De%X z#jtzz-mRSEi;@a#sez*6xsTjdCla+9uOJsCvBo@8?tn6C^ya|`GV4SfdH<(aOz=%d(2(>(p z#p@sstR9>nZ#~tfa3t2fq6}(-<;^zPJzMNd4_##1QS^}%6ox67a_eBz%eRSA3ErE5 z-Gchk8$P{IWnD@#r)|u@<6t@1t0Zuc6C4*GBOZ4G7i%K)%{DHYlcjQP@{l}t0tLzm zmrxETZ)|u@CO0?E2~AxVto)wuvpO|vHmtDmr9TaBa|fUT*-t>}L=h!yfi2mnkf27; z7%lrjy=;c8kp^eQF!5f)zjGU#N=(N>m8jdJ4z8?{8i6z1NHV%D*vF0i$2q+=r#XGZ zzVDuTd=7h(+xu$~?W(1y^4`LZLE`bSVTMr@wb;fm~EmDEL7NT0mG$Pu)$}d-1 zii+OwY_Yyo!htJPGbe~IK0r4Q<-6Hhsf^Od6Ab_MTj>|c4<5XWcFO%*!*|<{b&r#= zaK-;3uAWB_ zZs&GqhqpW{*|?Nsq_DIM@cg2a$x~dJmW(n|Fu=d72RSFM%_I9;xRbDwaNXTj?W(Ki zN=U&9Ln*a8#I@_Sr>CMF{(*kC;ku}ONsVi6k6J{xSBay-MUS_ZNC0lHyngRfk5Cv- ztv{mo1&0uyRgBDDZ?dxRzzM`t3x1+1JP(1_!Qe4GLM~RUb{KtqQ^K*QToBJb^+?fl ztv_YMMfg@C<9w4SzG#vz8f`bs?qr&tj7 zT7&uXgK=X6UmoH4JVU>fhO|A0qEm+&tA{+0^Fz_J?F3H4QIP|Yr$bzDUHF5I)5FEJ)n*Evy5*mj_*5+FT{`YH4h5x`m=kbjm`^l?>f_*K`GMs z)tX&32FhijqH{a1qswAUX}2fUfcwD1JH0R!18=d%eeq3NXE z>U8Z)SFhfzT?>nWaEMoR(35INX+(71z>rEBjc`e1iPx-qv-EG0C{dx_0x$BnX;C&i zp7K%T8YNMP6=GZ5QFYpGc$C*iL6nl(>4)R_VOg|uc{ct9fr_XFc76OudBi12cih=R zs>A!u()Zf~?{|0Ke|~zuN4Iz&yLf25_$_MjxODNyz~b5N;`!6!1>Mqb*`;girJJaw zyV9kHfu*P2rRS$56#C@_=zkHZX+=X*LPbT#007okzeKGceEq1n`TZDu`_s|hxyRw< z*Nx*pH>W>;Jy`z!dwG3>_IbRwwURUj>j;%>MsN@017yL`P&cUROQND~$(i|pRGrME zhD+C1n}`8+n<>{cUaHG6(ab-Ly>l<}-5?;!p#OtGo< zwwe!wVy}HlZED>g2K^divz~AJIx0(|wTN5f-#A@JtOs0J7v^556!QhjR(5>Xtu#ty z(CHsJ(Qj~Ubt&8Yq2z@!)%X9Ma-slVb7q5524pwF<`D{P$-d}zC zaI0PM`qRUov)CTrU*~^i!hRl1ck{EGo_>Su7sVZYS1}m1-{<{|1wZiiBO=J~5jql<5_ElB9Ob zHVBbq%i}c z)cci7JJor$ST@$Tq!cxxcUZc6ywm#JDBse*GRG4;gofhP_KslQp&dERyp!FbMB(Yx z*(`_qvtvb9>t~TXk^BhChH2qXw4FIv0tz6Cwk7ndk0pPoNo5H?{M6^85BjgUo5_Jc z2f+d@_bYk8{_C5^wP8YxClfj}n5UmEmQtmkepv0}g*vgCppbfusP)C)>*nyQ$xwRUnx*5P)O5BG@Hib-~X8h>CJwq7?n-dRjq}uFz74K@VG@ z_UlhUQB=bXUW+!2@5(mw-TTISe7-4$xwvxB1$WH(ThH%$RUodT@Vp|9@Ezx?76jy) z-PZo5&*}A#OlD*diRq+(W35Sbb`B=9v?t&lkd7v>5Do_T%P(JEbG zrWF-}8yaZP*Zn8BOI_W%P4#x;Ch%>T^^>C%$Ry$J1ZpXFA0`9V#2>J2ekxS18 zmWqMj*v_F*C`-ej68cA1$$p+6RHI5RXyMsz0LY0Bwh4` z>6L{>qI$tfyLp(enEF`RQ+Z!`DHD|)D3?~^h(9+T5Fk}Mm33HEQwQvI$cTj|+d&_I zgIP=*8F!N+b0dk|9Yxa4!VsUf~rF_2D0@aPxmFWUpBY~G!OpPclWvmjbZU=b~-wrk>I17>)m5%iaKj?j|+BE8Tm zeEGD)udBde0UMeg$9k%-oH^Y~llV&p`!YD1NsIcM_oiE0SWHDSRR=RJYu zi>v^Jnya(7D#^+pB%oa{$1y-^)HDR@Mb~e(5686zR}CdvjJ+c68U!61L1mU4#a@M6 z$wz1$fk%@JXSbq+ccno(i^(G(r6E6oJGp}f(5RUWBZfCtoQSV7@W|z&jLBWNf^;25rQ=JJ- z#@5g`=q}jqTLv%jqx~&;9VD#Er_0HT%S@czJ}qy40DtVL{gYvpDsOSKV44cEQSvIg z+Fqo|FL+8_^&Ty(-$&c;9ng6PgnE{iBVFu!r-b@8t76`DjkaabiuHW_ld7HTw>YsWfAJ2b*aD>%nG>wqX7L+9$sVxk?lvx z+hH6|zvyYAy$P?|5_jftVd7m>fUnDlc3WFD=UKNX{T=q5GhOlt?Y>}G*aY2jn-c>s z`mHMEB%L~GQck7A%19wP(~tutObS!Zo76m)_;2^lwIf%7sgJJ?sBz`R{c0oxk9#C7u)KY=%HPtt zZ%{-m=6nQIop6rXCT)M9>{hIo2y~Zg-5xT5iIVBPlVdXp$Ep!$dG{#0$bBfy^Nyga zc{=WxST+^`L`Orm*Jd=h3#8-_P)#9=LkX^BbDdW3@Bcc3#1IjH>C~TzU;~ z=DziK>_E<6H$9>q@Xyt~?D!dKHL_#Lbc4%={kYKc@yhX)Qr*39gQ#-LB1G+h zM4J?TnJ#Km4#uhYvh*2T4z+!$^vq2UvAwZ)(}Vc?(=QXT`(5|8f9LOc*wX(QsnNZ7 zP#?+g>Kw-Sz8Hk~r9gGD*K2c&W_`cBL*U0QXtU}QBWLmS68$7I@d246jTg9hv!9dj z<5hCsc2))Pg(K*RO6ZjV?PrW%naU@gKGCGLpA~wnUM0=vzd~+&svtfytN3f39F30} zBLwwvas~Bq_<4lJtg!>0l8FZj-jJyQu6u*sZbA6_F`^?N?%a^+d_^4f5W28{Az+Y# zSuC+x+(CUH)r^eEa@=ho=;7A?1uT$7(&z2e8(uKTfDyz`6(l!9WR4P#rU1eUiB}++UgoZF%^{_w-l*Hlh0k(ydK~wR& z>@JoU&U6wI8YlWNG501^`&fKEYl&5s{R9+?L2x3I09; zHZgXHfW6sO1smJ}vdz6S!1zfp^x&|>br*>1F~9{G7QAbkVw=qLVC*gI;@}7OtUe}z zN}`p_$ak5hu8{&^VEMK%2M0m>uAbCi({@c^9#3q*vCWwJ{4~K2wnbEK6<8?~$4N&a zX^tal{A6x$PVm?m%er}*Gg10&W%@^${^_Kv|5!Sr+R-8@9bYJw8K$nI8d;Pq0Mq3n;2WW>by14+vTZcKChF zSWFJ3yRo2j&!X$edMLz52u_Gq%o1qJ>btY0)qom0 zsEOFNSYk>q861DFK~=6b-aHH!#Bkx))iYS=yWs}*0MF1ly5(N!8t0H0p zY5=cPCiuu$FOSngL&1?c-*6;H9%5?Sr?hQvqT#szfiFg5D}vR>;Z z8qasC0g<0zg1AIwGv>I7vF0EftN`87yuXV=KvDTBMum0|t_{Ya6W~y&P2f8Ah)E?| zBF*BZE!%HwUN!sK3FVVNSsmm!<3Puc{*}RYZpz>2T4w=E1^=(7g zRbldO{yo%eG{7ct_rYwOE$6hb{pz{|<*Fn~2~FVnk(WSH5#NW*ErjMs1J^WKNiY>n5aSdyqn`Jm_= z9-P&WU9*}qM+ScRLGKAE6$}&6so3@{p}{tGc5$q#Z6=a+oYqL$Z&bZD?9ilX@W46* zXf)?H6=>AB9-1$pG!=@J4=OaFM>vnpSU{Ls9~<@1G0W2G2tg4;Gs+H6A; zYYRtmM^n>9DLRfuYpB>j?#`4bxWx*TiC=5}X-+T&OP+MHMPE?DG)JzbnzD2*`$3wQ zK@t1TGNYH2KQ*>&ky?1%QSj-9F!pIfMZ7S+3|85k2suR9_XG9zWgDx3G}S2)Dy;|r>;GTP`I#Ms*s~d z*Owb2PAw~8&#oFIOjP@^Mrj29OLi$MnwTCg)#-7ka$vXlPP#R19rabWhYO`clc&8^ z&*X!$TV%-3vG&j5V9!WF;+m337e0TUUaXw5@rItzoi3zew{I%?nHFmer}XHnE+MFE zB22gHGwtfXVeCUH^yQHwI;<$(@er3-X+)j&4c2tL(ds7@;q1NYpIGVB(?S@>^}}lW zLp=x9N&6kN2KL7WqE-+!_JecGgO5ssdh>$=af8*>gWrLJ*0dc0PD3M_J#MFiVypv} zO#_S~?RH3vAwHfV4h`LXt>M4bLve=#e7A@fxWf?EVa}T29@Qb6_+i%5;cJfv2X`?T;_UTU0X{J^s@g4OQ$v$tyd5yvDBr&zP_f?1hF zPRYR3$dZn(=*VdS)UIl}PK7|t!`Qh7YmO@tsit;<)Tg;hmTub!*R4IiGrRd#(fTryt_1q1K zZ@lL!^pfSDdysd3HwrzT+6_P;l%ZrhYYYmvsaV`{a=Qc``>%{N?+iGr;%GG2cM=`f zHtY@QGQexmi~;)<5GS3P10DQ2NkD=Czw7ICZwpRGa_R%O8bZ0TKl>R5%~Y(x5)2v? zDaz~$HQAp|fJdfE;^7Hkqn1O5eCA0vXF|Pzlk!{#&9`3*UR|5Jgv+;RdoprVDEhKp!P3UMBmfu^(4(@q? z6%?r?)yTPOqtkXW_{TG~3Elb3)-s^yPvZ_Bo~+7cG{1&kY$2`l>S=Z@{_amLRz7fe z|DzA$Hv@+6U}H+kuYvvZCZ56Pq#e-k8Ja;x7Y6Pb%INI?DIv)p*5-?`XK8H}F^()5 zA&hg&GnJ`1AG+9XmNEnUv62*Ch4%0s|1}u59!isA;98#B0vTw#gF)a6BoL5!KEU8- z@$98gp-8$SlB;Ul=CT6eO?OrL=4AfM7iT#1t=N)Q>wnvM#hGnZ-w{y+X2+}ps{I0WNO1pt$%*&Emg5kAzf-1wQRvT}FVAM@ zi(QM}zt|4DAB4wNm1S`@?04{f67#j9S>$8Zdc#&KMk;lq)GGesXrZ=#IKPP|9Ex7V z%zaY+R*{)~CzZ7n{dgWqZFzgOYCEiO;TZf<<{?!<(aE*Y37`*5DJD$sfew-F*TfXM zzo+Q(Zw?W?0HLo=b$Y!`|6#xEesaO+)Ppigm~qCy<}@k6@21FajZ4WBWsbXU2gP4u zPU0!Gr(t$bve*+$mgZGbF*HwkF(n9g#KOjXX|GJjOpMp{+nzM@PMOjai^Ay1o*db| zOv)@Qlxn$KO%Cmt&;qqX9BSiCjKfq}>V$AiE*;pnB_}1MM|qrcG3YzprrCHkL?fFW zUt~gAj4(*j;(6n2es6-6%7wDlJ@B~b?$yL4kI06}q7<`y> ztLdEa#aYx;D+4kcOHtkBq`+oC;e0{KbS^&od8>nLK!^JgQ$+ZTtuCQN*EPBjy}S0$ zpDqPi=IkORCx}n1fpjaS>|*w6bZ)8~CEL3$yTvTp@*ty}13K3)?Ebnzb)*Tq#7vw! zCySwTXR;f$=r0Z2m-4!&OU8FyIUnyqPlqA|Xm8jQs4rfCxcRD{tU2T6!jYKZ?d(c> zs{|E+2VI=mz?ZZ~$Ko=zWzdwh!qe36vN{nfwg-fAm^$cMkzBe9W#4OLOSp6z?uP-B zYk1OZ-^7ii=}S#TVSHkBIW+QMM*SAo9osXJglA&bt(Ly0wyo0#EiA>XTdzHJg zWtE!mr8%wYhVWW_aHY4mcN1tKqouJQ!0fAlVB7i^X!#KFdHDaXmRD@$j|A(AC?` z81cyVn{OMaLwWeLPmi{LX@c-E{;5;ZqG;eQOrtnMKVw{Icd0Ce&p;!Aj$#B#|w)$D^r~}|XNesccK&n-g4JvBzl&J1mG%fA{-7STm?8kSRxYG9Z zIN>w+c5SYAO$iJvQj-&qOVZLbr%noLJY&_4Y>AwGx;^+@)O*65bm$Rx=AGDz&Ci0- z-Tf!K`x&p0kyKj|7v^TEMXUU@+!DO+lC*cS?&Sd$e|Znk1NV`O(TgIEKkzV=Nu^)K zy2RD|jrukzby)UG7&HV40*z`S2 zr}{fPGeFgVKo5LJ=?z$-UhS_P4?88h#oE!a)^vQ3rCHs4`VZ00Sm%n@^%~o&&sU*I z-mYG*h~=E4tlr_jj^^{`9}itnaSFefb<d*H6tKf%jG*2@)q7njeZ?oL)ZB&8f(eD zJV-;})4rH3d?h_PC@$V)*|@bo@Al_)2IPiYwmo)Sy*+;TGev(P)={by(plvn2{nwTqGP zuKyDG`!7k_D}f_5-@8QQQ;jbYdn0u5Lyhg+`cTZ?Cjlqq%*L;as~zVfQM(r>t~O|r zfM*U?ZAu?QXbf!M|1y-`_yU9-7qjjfqjT$Xg9>U|i@sKk$rb{!`+*+Rd`ZG67~P_u z3ViV3OvY_-zS+Jvu~F&yvGnHNW<>GV-{Qi80L+rHhacm4%>mNtY$xAh)0pBF^yAiY zd^C^Aw>UhSZoHMK)GSaE1n#^`TmVLH?9UX5X3GgJBA!-oRl@wl5q1|+r}zbzgz_$c z=_d1nc+$XCqRX)dG{nu<*~_btie^*e^|42Qx~dHkI42+}rVwBUC)WeNj-2td^>Z#) z1>0N$eDA1RK7tXqLZQd*5GqRZn-?6ChHh9Y;YfA2LiK2SM#v_*OJf+P{W8Ru%C#P> z;jpaVD4t@k50RO15f=xx%_Q30q-wQ;)t6IE>Qa@}fiqO8O5&*#X23DYWWJ9nA_{35 zjEry8^%vn$E^TRsu?a0I>ElYk4`8w_H$8?V;Dw6gkvZ6nF@uLVB|d@CV>x5;gTsv^ zm8ZTf$5f^VN~Xbt{rz#u^LaCf`3`j7E!&N@6 z=V%*XHmHE$Dwy)rWJ|%h4DC=GA|?)Gp9)t)cF09G;L5^yRw;}qZ}YpQB?J`amq#3% zv!cW#OUk4zrEXV5q-Oz;wjgJ{&GuetQAYgfV7JiWy+V49Tta^V&k}#Q&C`d zKr-anu|I?pQkf)wai@2Fo0NmR$d1h`k65FF1~cTI0BP?ncJi^|CzftvYVc7jm2T{{ zJL~Fo?0jI=XjZ8MW9j{PrQi*AtfVb24$i9r+gAIk<>N?ZkHBhu2*o#QRvhCccs1Mz zhi%hAEewab&=K;XT9hnFa4tP4o>jCbudy<609M>&7a8pmwc%bk7me zugk8YL>*jHPNU;p)|U^D;~|RQezKtMo5P+h7ARGw2}H+R!g&j2rCsgEU7xFkkkM^< z;O=mzJFL-tp~2nn&vCz|e;$b8wYcsL4wlT?D4Y&#-EXULsuF zDR91ruSF#E87VA`^1iaAY0rzwHu|A--@)yp-Dh* zM^wbB+pVNW^{RyZpqt52lI z%NpD(d)jL;DhMv&hHkTdFXqm{<%Z6`e9Z34R+Nu+gd2T@cUHr7#^AB1$$!xLtI&JD z?DwgQ6oRxIY7tz`TC&xirQJMSb*J2&GF9GIyuF@s1*hz7^K65({4I}Fj-H5;NT$h1 zI6{kKmPdHL#B0@x9nVv7blh@Xa+s zwh>(rNjr3*IPAp?udo_~mkf=X4bcY--H;7ZcMmBjj(7t`L?bmq4~D6XyCQi;Ht%dn z=z7VtnzVlJg!+0>`loT2 z@P^ww4XH&%g*S&q4h%P@GI(o8$l6asnkf@Y!?hzj1f!T^cq4NL+Cz7#B(x$)KtksZ z`t24nUF8F$7)*SzmjngYbF3htZy=)GJwn%oIT?ldo~U_v>3sjd{J`$~(9`_L|E9w* z{#VIg{$-bc+2vn$`Ts4uRPx4k1F)j~oNfh~c+ULCB>rKS3J)e)ybcA+1&t(kusXiu z<#5p6G9I~sJ(vE?xKP4jT*Zj(a|#S#IjIdQ>8>1$cx}(>$#CT&7v)5ai?+`6*N9kk z!UG71DJRoKk?v*DE9lkpcvvf)eyk6gnG>>~Ie1|~#@}Lj%UcH*C3l{?RMj-|_#cy2b;JcWm7_LOJ<+TU zNZYkmOeiIg(Q1u~ibGzfZbWm}(LCBMc5p^a1?$MiePcGPcKBzywc+oSQms%wBIn2n7LRxWIV!C|{iq6~ zKfQx^a(1}S#DzY+h3G7c*3=h|4g|152`A`M4+wS60P9EF;1v?tcFgT4GI(^_6id=2BSk3oekqCTot~?b2(+&RL>5 zoWm&JA?}OU*QZ=6EISIpvYb+90azcO!^g8M#Inn)^Lr#(jGR`bBh>XfUGdUQpGe`| zy&Lm*@~E16P%8I(R2|#mYi-phbT;X*&;STQG8NDS2zpi&RuX=}BwjY_J;QYo$#W~$*6xb& zE8G$E$+iluGnT~LRbYSv|2yhfk%J%JQ%Rw|Way;AW;sYC$B%Y+WJ0Ohm&*ESfyuXJ zphn*}rG5a7k1&Odp=GjwmQv1;s!vUJaX-$L?z=ehmM<#ovt%UD=4d==Y&MJJ)I)%t zQ>S%wHPZ06rk>4~US;24CV^;;EB&!`1!!>tp3ttvdPcS!F;r-GgIfItP3X%#sp)e_ z4c?n`jaI~`tMXmM>0tSHh;-G{^X+s*8McS5>Hdr55E^NwONjLo8e^;M?EgE1N_s=T z3znX~$sq5SGl#D0_5S{_LOyIR4c+uE{XLIFKJF0?-%aa1>qdQjI@TM0*jReLLB#wm zs+Zl$yLf)sK|cS=e1+V65r=$!9DXj^2*argLYjeqVbMkPJ{Vyjyv>+`&|o7n0KR1G zZD_c^8F8E%IvG6nJT(0G1`o+hEOTLW0S8E+3&bKBSMWVh4;sf0k4xT&<1dWM#*D@0 z0EociQg364vtkVk;^{cU+2MpHw`lTI390q|OkoLR=3(OS5aF2wQu8oMP7+F%M5DV< zSvTH)hK(@I!?LDWUeACcZWA~af>;EToXkT_u;OfBNyz$8s~G`FtYiQzblU|G5|-@d zniR{L6nPAClSl@}Cb1HMpKn8y;DqKNaNJCA^f57UvTKHUto26H%R)e&8$?YF{G^{i z1Bal@1lJ=&0M%|WYLt*X*OdCg7=`bUM?nbfhm@b8L5=K0UFN9*^(o}`V8N`^GuObj z889A3+Qn@^ylL8$dK}Yq>X#M3JS>_^BJFN3m6Ira0q*Z#m$vDaK6#i{bPV_e29c|! zb6o?zs%M-7Gr}>_Pma^u6Cl!Lz+Y~DPC(!Uv+;QeN%mlHGy3?<$2K%FI!!xEy}@?f+8 zv*%>POtW7*0qJKw(E_qH1an}fS=jqo=?B@FQwG<2IYD(fK>M6)j$Gd!TleKG*)2t7 zWVnhKC?~Q`pPwbq?IxE44%C*)`~3%K1#uCaCBTPdtKU1|l3?0Gob0I;-Q4p8da`A< z@_lCQJx_Q$^783`1y6wmfm^R>sIy-~3VtT$VT)SEg}<(LE=;ztPM}T=9m&;kmx-9o z4nZl(f=CCu7lhdrt%?=V_7y>;Y{FDtR5jS-h!K=FSd??AML~-*{uEGX6u*V&rx)eH zq)M*4iXZKA&%q@>F-rVTF!S#Pe;Su$U}KGk7rm+}d8{n$JT8`HlK_a7?&TJp?UgD* zOE((?7a)WkRJqF#E&7f!C1~j+Mrk`2);2_I%DqI>u{?I2X@DzdtwEDTv0N2NR1Qrj zKjC6X)lmN!PIwp2=B%O4B3z+mQCaoY;DZA6L50b2EBh0tP9ixrX|aLkJ=OjV;CPHz8Cr z4SKI7F=$x9A~+3XVGsPWC}g<8IxBW_-u} zu?dbiEU!#)=GPP>tQGW~*YwZN{)0Cb6HV=54K;T1XiS0%qLc+= z)(Q&EvMH~GESZ#1RXDdv7gOj4a?P~-Wk=ByseUlwGrgK{)7ARj=)PujxGlTdX7l9- z-Nu7a$xUUPeM_^D^>0mw8OD~)I&~+N)`H5`2B%8hqgDoK?|fw=3{M@b>DIN}HZV#X zwqn!nep@_|R320N;pn>_`#6_e=U>|ZJ&4MtN_&k-wziY;3myQ)4&5s!=D>LD&trtqC?|QB{ccC2{ zVV!c>FKbr1t}nW%lBN4rNQAM4GgoBZS9hnoi3on}{(K;0=GL7}BK>$k@VO0x_$yz| zxZqDgjE{B%PqT6E@x4M8>W={uAX<3pgkX#nTn{Dl1qW$~y?N|QZh{-{;N_lnmLT|JHCf9M=~-5A1q4kEF5;hb2E$3T=(M+8 zOK@nLm1v&ln=nuP4pD=Qc^VIIU!+8FM zcn86?u_N;yVYDv8{XvFvIJ!Lh@%M$1hs>OD&Eo1p6Oa z{@eMX@2R4bR*dMpj({`vM=Rwo^K8f_R<%=;RfPQ@E;s6c7&cvdWeKO)quS}b4CUDn zrZpF#tk}I33u$Qy`IEaeBNtDa{$EdKVqOVq-j^cHOkx9!5?*pX^UN|)nd&#=#XF;# zE8{PeCpeua-+qp>eF6E+JI#J@)~*{2S2 z$98g4a%m?z4=1(~roL%SjRU95CnoPsC*k%}?UKE`LM(PB|1v^33!o-h5Qg1 zeV2Ur_}ffEMN=&_l`@o^DNMA|C%+&DyFF$*h~Zi-OjkeVZV&YRDDZbEgGs0x4i*5& zNsP7Wfm-NiAQ-3H6^7?V#3YH%4hu_Ei{;AoCNU4Cp#%ud5YU2M_^86E)fsN5Jzv0- zjENG$jYGK#<)2OCeJR~dMiPR1;{((H5>$#2Y6S9OaJahNrzqNOsPfZ|fzoxgKfPe%7N^e2wH6XnsQY8?2hoDsHy~l*! z5<(S_Kq!GgAOw_N1Qi99=8CR`BD*NEQq;WJea>^t12}4x~Gl zb@~JCM}@+FTQLlx^BvYG{9aseg;1oA^Pp!hUd|6?a40kv_3D%^V#lyBy5?UvE)Ga9 z`D{?K%2euvV>zA5P`l3pBA+WVE8Re|uwhDQ9OjmiXUxaat%l;Ps?y-VvM}zl&x^&I zeWgE+SWMc===($?=*ssD0!*lKrMFDVjHk;7fvhHE6IQcwBf(q;%RIpIB1=M%_OY+; zF(N9xY>TcUI=hm|lJ%acPq?cp=8kvRTxs25#hz(}a|o*oqN4Cl1e`ZxACU7^KXV=m$6{O4a1-V@+Lc zMDAhDMzJFZ>xFHM*J#ZIM(;U$t+{CJOKt5zOtol>SdW_c27;+u(0W0x4q<@lajNkX zw7DZB~EjRMg~zE!r%2?gX7vLp@0-Efg){WiBd?$jXBvQ2R)~NI3mp_#h<2pXDc z7=>xBxiv2Ohnorgwd(N3B&aU3&Sx~dXxgKN+na`F6m-}gz6j;Y<-kg}B=|H3D*4Xb z4{GQ3prILXxz*VH;N^6<*N%VJrag;*K+mEbNQNJ}qjEJEv8-WKArLiX56F*+DWJ`2 zcw@mlt-j4S9o6htk;%U>Gg**7+9sQ#v*sxGX#~Qnx zKW1F0Ls3ls4erLwT8C>-?B;UEbDa(WA%|~jol81gkF0P;Ih`v)=ht6!{f+W1;z2%4$^%&+G*e-N5%9vtQJT4w!4Q}Qy@Un|MCO=N@?2Ic z1(82GDA2$S3QMkrtJP2j>rTlHprI7VQ1hwk{iFdLSm8S09R8Hl2?660#d?xR#Cds= z;H3coi42fuavB-|_di6+8CHu=%=b;5%63Dp%~|)&17ydn2cISppC!pq;8HK(#8(vQ zCA{|fY42;W^bGdO+ufeuAyRLwbw6Qy@&WRzaPS_uXB#BBONC!MNFp2}CBDG%$CU2V zdGYT_22@!0p8(mPAXR2m7k!x1V}Llori=CS2-mO#k3#1;1uu3^O#y`tLE*xw<*`AX zF}o<;V##s*$=EgMSXbsa%zE6PIOc^Mm){VMX6z7gpHP#UPzR0apg_7PL%@%T!IrFJ z>&fSbfd|M*$=uLS^OL{$C+T1#cF7_RVT1|Tl&8;lUgeb1f{6R)Nj!eaB68}P(2)NI zFmR!x6gw?BGtRS4_F8a`NFLAGo#q(Rz)2N#mKuH{xfgse-~yr8O{WzGaz#Y zWX^!h8IUFOPVtva|UG2fXx4NAj8mT9=ZaMEH@<~RCiVsLqgi5 zw%hus@xqyFcScoMcI|&OD=|*CJNLD7mEC3FHAxo3_daqrq{r8#;~%WS7;wA~ zbUKFRRqnW5n6&Ch=;xdHopbJ_gFff}%Y%-^>V_{pZTAd2*FtTH_8s{Rotrv%W_j=5 z-0a>acFmjkK8^1B+>RV9!(|X&`c;@YlfTa{bYH)CY65pX21VwKNJGKk|7pAAq66J9*dLO zW=T<}_}jZzE-mFnV+SUL{@KkQVRF=3?|ft?f$|`Ug?+^=^wxL zbwW1T)98n|N%EL*?Bt2y_|@Tn9ZD(zFnQymw&U*)t&+>^IT11oV>Q#0-4sU8n|tzu@h8y#Lb!^U)_gt->2caQ|n1Fp}Hfs$rR^VjAh3#vT8C2k|oMAF#780ZEmg?`5MN^bgE2qIKu~m`^G}%{Ez+CRran zi+SXXPj1m|u5~9qYkj2hc~%Gi_mU+LC7QY&~-ZYtCTJ8LT;jHD|Eq4Az{%nlo7QKMB@Q zbN{71QGf0iJv?pvXGrtw=;=f1uMb?zkIF{&PX*E$&}l!-<4ZNu+0f~`tue>3X&guC z472HbV(~L985ePB_Ow+^T!t_(&0#Yd`6@$vB~?2pJxw!H_DG3&HjWORDIv>Dv!nQ+ z@T*6e_7QgqBGc7nGab^iCYs_PD;W(hBgKH(0v61N16SxX7FFIb2ZYlGsdlbov*K40~WMn^tc4L2RIGuJdLZzhTTse{RsMgcmM13Yg)| zl;a+k7oVT|$tN#4Kf`4+_f2MO#$XzhJ4*!^o0p&OvYDlS6jfl6?pmCEN|(o`jyP&% z&IaiYIjk0&4bO>+;;#ajBPiQTLBf^0Um5A8#*13;J=PGw1@^wq^xg z@c8H!Rk<)ms?di!;H^c0154Nw>B5gVhGwA27E6)Y{afpSMSkAMDs<7-tkcd>AvL~e z+9HdQT;zW}Bu&B4Zm}R>lXtd~vJ96Q$I9RFZ+e)a=u@B>il9POv`4uqk zuM&`)X#I*U7kdeViCEHT}=#2JMMD$%hE;u za^u|caJzDC>XHAI?b7CEJ3H<2FoUw7fpQymR@+s1by7v7cZp)Que~L!@HP*a-7?^x z=?pxik~W>Om#e7i6SY1v4R>XQVk(x@tKt_c9Ai8aLRgdLP=ea%J9KDvfxOfsS%ZuRW5bgtWNxPO~;t1rW;iV%*RYnoTYy2F>6DD z$;ZCxtOl_fIb)JG8xc`y#E*U5EY@wQOObOF8L#FbR?j9dRU=X>oNKz4#X`usk1%YH z6Of4juy3BmXz+-@%dMOwqRG=hCU5u{~(AV=d;&B-5;=-LrfdHfL6WF zJO$g?i$7IXudpL0e9E@iwT>$C&?Xfb{uw}y;i-F3D;g@&<$+ophNK|%HH$Yf!9Gw9 z`somtc#elsrG{t@tXcC_9EZgHV#{`pXCGqZRyg#eZp&_Q5c>;-k2o&9C@^OOoa>MD z-~hm-P#hKj%N%5Y)!!?bFem^$k)IL_aPiMC%m)-Y2-v1@9!@CxNyH@8MhwzV8&#hP3PdBwA zXtNj--vtBwP^jf|XU@g7+qEV)$3iu3X;`&XboQ&=dOie-_G@KpwRo)DRooceI3@Di zUA7Y9y)d5nvXNr_Ov&|_%Si}mgO zCfW;GgV4;SKyGEUFY%E$v5jUfW$C(U++bzcZcFM?#q7S?{rnTzEtnXXtDcTjb%q7JgLvjv0vD9V0XNC zTAq|J53V?oirXcn!mkKnMUt`g{(yd(x)e2E>$R&`eOLO0yh0X4K7IGXt)!kJq+&^u zW*()^jdB&aE?KZHjK#_};kC;ELm@E5Du81B{15^l-@OiL0YuTMg4=fG2a+0F!3va9 zJxr1+87n&my4nMQ&acbNfDGn#Ri9bQJO-;gr8K^RNuOUgTBo=_gv&0$OoU<5ox2jE z_)0unU>hc}x~usX(liB^eM3Dpp8#F2*d3|`T=_)X+MJ5-!mxYr;5*wxU$A;F=EeU6 zd$Dg^19aHa+lX-q8(f7+oZCph5j&O-c|dCfXibg@m5zPpXlAZ4KLn48hM7@e#YDU$ zqj1?VpuQ0%@%=PVT!B*ZUP3cDSi9y1uZ=MHhl8p+UT)aic*9nobL7%O*H5I=g!OpZ zvk7lET37~nEh*jF-PT2S>c&DT%;w=K;HH;CwMYi#dW~CvO=FPFu%80xx?z%opNDy} zkEMH&&jLhU7~-^%80}8HQzJn$m&_e6UceTQMA0xd7Y{rm#(Po>#*PF_dY;8fP5Uxeu%P6k?V=0B^= z{QE!CI8Gbp#FK77W|9AXyUW+mL8<%S5>i9(1i^6Zp1o}7V27I6W2*6D=OK`)K zK-xFp5@OC48qU$P*<#_#R1&E7eJkXiKMtc+XMp#7&V~G4ogr}QG>cua`^#9F$v(gL z@9GRXM`B0m;<%rOl%T32 zR^a56BXIn7I&ajz0B3ja`wm+VWcnFj*n+_2yiIfEY6i?2 zR{&&$({0%*`IQgi>h#to4AD&E!qU>W+aCGd6~&ZJPQq&tHo@}53-{hjs_S__wz)Z8 zg;|$o9XhtO;!{<8r^~NBBF7$KC0#23ZIzRXv|SvFX82koBZ&@qnsiOHzB79=?gzU< z`VNt2wOrVc-`mbjW4yN4HP|?Aj+&oXI$h7(f{UdkYET@GJQr&}YUrKVn;1B0OGveu zo#S!XuybqyJG-rTaxA4^yw^gp47t9l&6axMlk3dJwjpE2Qq7JNZkR9oMwXwUrnq`_ z#-bf-^zm}@FQ2wS`cNHw=!M?l&LwJ~;xoB*Zqh&uutmX|B1|~0(Rezz2LYjMQbnOdGUq4q znU`Sv^~Ffou$n2gGiQq7%_vW*g$McHb* zKo_9#(E;y1f6``LqjGqV0CmnCL049^YjSRWs_f_fU_o5%y0Gx{-mQ%-u%sKd^0)ow z?)|NY+&aqut#5osoK@EWt}h%mW!tH`JIK{f%fw$-I_m9qhLhu8QeqkK>+g0XSSjp( z9Y=MAqXNNf)yjjOq%JXJ@F^c1 zT4$^O7&|cX`lH;pM2&+7-(X`YgUP$F4krTXVTi|{(21Z;CdDJ(x+}l{iJHEhT%+Ns zpAnYe4fgN10Ye8KyVBW7;607#8H{)RUD$9pi+<6>^}3yWNXFayf!ZU=BN0bo8*e0T z7)?LD@KybjFgt`AUb3LPe;|=Oj4{6ab*d^N1}~{scU2}KY1-opPI2txjl7eAD!PN= zZ|+Y_WyU8B>khfxM7CHJlbFY^Wj9c4_cA?n{$D>``aj-dL!N!({qlNm+Q#UMA0qC( zga`YRpt9FhZ^|lI#ZIh`b3ndAOd+(+ckJptzJAnEv^RGb(y%b?`rSK;=>=|-9RmN1$?Y*8fzS!H&qnXjI8U8cjj^=S<=oIIO zj0wkB>3qFkGq z9we0M#?du4YE}NAKO!qXq6(Vg?S1zz%?Pu~K&))))r&0kINgI-_uedMU+)A%i0!C_LlcMS)N}~q8mUcgHfUFsCT7w0azIU*)QZ7D=MZHfE$Wz?1P!+ z5r^WlJkd zR~~DsYo17(C+^U-fWN@mm9;v+>l&u;4xtR%?CDA7+5?L7d@Z-FsEFsTJoPSn!w5z3 zmo~Ljo^QSxfbqCJr^+{8IpSB&Jja?W$XEEHTxgXw)0M|)&Il%lO5Jy6I;<+SxXGhZ z8RUc(=W*tXLbH~m-M3lGSHauw(Vw+w5nzm|WEFhX(c#dcDZx=F6LV`0oxO;u!&o=8 zmFL-EFP2#M9v9^iu+v6X)otj3HnCnc@kC4J2V}0^Y^*JrZNbtU?_d3@mu-xUq+b;a zTxEGqHbFG2bG<;|m#d3JtCsmNB}!>eOv+DVF6}!Nm8D~UHKR)GY6DH|Vztim8R#LO2)3Xn-jmR2*L3@W);Z;|tc!1X<`-W_S7I@YPSMDPq58_&5 zm7Y!GJYoMc#=pCT=Lk9iL|I@SJHN-x^y-UNsbB>04K7=l2EL(9B}n;UGsCTgJJbwIIiVHMDhSGI!8K)HOFnbDG22EMmR(t zq53y1ZoC4@mzQPcUvS@XUUZEuLI5&M;vOdezZ+yQE(4Tf;#f+Wnh8b>_U235011;2 zdb)-<)hdRv^XAn!RJ+pA;(ZdgVeZhm;vuerc20mluBx58lmo!Rhx$ zywFir!xEa;zPY{|df}^M{a@sqwjK5bC;X-7+(fr)@A@S3IRGOk_dl%aF6{@e`-cvk zuz6J0A$U4klsb4;E$4GMpRZ-V-WH^Ve_!cXRY`)@<&6%%cT#w|%I;>Zo;WUYu)iM4 z(Elc~JH%Ep;UA=SXMTs}puN$QFW|e74`WLy=f&oFgn?FyKpKcqg_=|r$xxU_Z zP9a-jCX4O(QJug)37N$M4SIid26zA$#e9z_eQuW(L@AX>k`c7NEQZaRq;Z%Cg4#bK zQd4j5x5ZwQM_T`j!_W#cnZ%61e{&dP;uQ5?37OG5qJIC)Vc02oA%6W{OiI7K!+Bcc zPsEjBsw6KMDG;tki~U-vkghio8C@XOqGtv6Wlx^cas@6{zEb(nQc%sk zPw2c->RsvNdGS=R!ez+i3_xKxelTbELfm}+E#H33n&ch_xM*I!3dWa*bjSiLFum6- zfD9zS6iSfNWvAVpSa2Ii2Ll&r1gX)-^fr`I(j6$1#G#82O4HY&ZKM8Hq}(X{TK%r- z+^Os|M0o(zh=73Sv6vos<0M@68B%qLBKQCz#XE2G#@hF(b#D_yb{H)Ec2`0QYw=)u}thH`%2Hmu=^VrbzssS2y#5qJanCj~IbX3sdF|O`n)(WZNHY0G(py(eFem33O z!k2>-5<(Q3u7owi!V;5E5A}ZtC|f6Ge17=3b(R*G(WM{LQUay@NHhSo=rsuB=q9&m z^bg+Bnq_=XtP{TRa`XJY)}R&a(NmLu2+ZPK2Z{mccb;wR+^@xHqRl+zKZ^bS8^1jH L*l~$QU?Bem`Nj3* literal 11493 zcmaKyWn5Hk!|jJo=>`#yZV+h&L5ZQeyHmP*=8v*GCiJ?;gWsdjrp6B=8 z=gZk2_iyiy>sr_PuO%%jB`9Q~ji`-yg93m;p%)hyot>RiQ&XFpn{YTB@Slekj-~iT zT}|?n@)urCZX|@iFKHi2xRDm^t3uCf^!b zV}IJ?#6Iihu30e513SsEQzVR)xQyEi7tBH2fYrLS8Ux~hW1rrgx?dvLnX|`D zKGXbW+gEK=rLWg7e|2?lTs*^r>|H^jVIs)-KG89;aRz?DNy#ax2;mu-S;+CZdHHdP zX+^~)!CB>y4><)@)iu$Dr45Zu0Tr!n6qU7I-95e%%>#o&E$ySO2)&b2(OdJ zLZ-gFcO7Y8Whs%i5Y;)Mn)qxsr^G7MB09ms@~vDUi1+-UX=hOpq0sh~XIjdvnQEuw z2Jm4TP#*)`(~b7Po^EhLt9PK3;$ZCX>KWO59$_}**1?+o^PFC5B5wr`XQ5)MH|33Z zTkP`tSJLW)A)?$?F3XwOh^i>t(q#J`&6L3ze_@q&U7XL#J6C;!=cipu`hbZ6`3 zb{`1qjbc~Z_5N52o6$^H`|Z(Ov0Q;-w-4v4n}*&tr>T?PIZzpiX1e<~%Jo4~9koMG zH|jOGyb6xB)$M=g^R`c5kCP(V($84&&F9Sz`Gh&k8u zENhU)@{f+!N_ZMZs45m0?>7>ZB=#m1G^CR2m zLW$DbbpT8rrHq{RFZ0uB<;X!Yc@op!C(OIIbjkA=Up_8&)*fk3z*94Qf0^}2I8|M@~fn6!@eG98*JB~t6Zrb}c zEzpL_c2+k;Vs}u z*o$YAYnQChg^`^=v2Z(=haNAq#m6cy>F=Zv4!f&|IxqW@?|cWd07?wp{n#m{PUuRE zQ)b++wAiNy-^%=sD);iRtnVS4M3-bt`Ne zk!JoTs?~iT)xG+P7@p3hC?tPX2%^}}nFSdVMcndvA5*0TESx+B#0#qn_HaI*H7z?n zpSK;=JYRJEym-D`nmZ@BB4P5`uoqwSJk zeQWmT+ST09^H+#xfGqfU_WDCsMW&J6vyS|j53jw4k{I4TnmgRUePHXwxb8z)kfOLB z!45!Hx$lwXhccSJG1AsiUmBm27s2O#Fi~XEiw!GCP&xJ`pRSia_zJ!3boyB_v)S-- z9lNJ7Eo;yNzsT=d)y@^!%$_9{97i;hf<%*%xjoiH0FSCfD4Fr!4&stP;<9ZSKq_tEi*g06yejlfsS(=B4C+b7w zK7>B4PGrv+Pm`YLjq}}zSjZQ>Mhg0O0TyFY!Z%5Yu_g3Ovg1JAo8-)?5=MdXaYdh- z6fkxvv$QM_0|pC6rq^PL(~kIvVnS9)4{YJiE1RhmId6)HD*Agw8eAr5&k!aqn5C0TBOUrN}y=a3`Ab5BBE5TW^ZEErR zX>wfAGS^(4I|PwcSuy8 ze+x;?huG9%w#Xad6KT>^3gOXy9OfkcE4!o z&BYdc90HrJuwpEJTlDy*T6H9ZsVRb}sR;hg_?bS2$LM+qu?}JzlFFE~1WdpRsZG7C z0!t%OrZ(s%*RlA~6kvCbx2)|$kPuR}uF;vt{))-{OVx*8x{bmL9?5=BRRnxF@f|?p zniFGtE3}d|sIVqwZs~ws-Z$N*WKA0#(`p+L?)93H1pm%^fNi6R4iok=dC@t86BZA6 z502W3(0YGv>wddINR>fe&w&(_t7m}z*^_+LVe`175)lx#j0T|lisf?}b9*7~53@k< zHLwmleG2KkuI}^nPud`wBDH)B>kl+g(eviz>f<4EV!QH1GNuzmeJH&oBoZw}8{O$s zip&c$+gY~1(?TY~*$cP8GXW(08e&$gkJg&nBkBA#%pG4JYbC!=vHojBaHc-qb84Sj zj%FzTms0>wt_kcZ6OkbxEKz#SWR2PzQM?RzV0>qONuYx%>wyB&=rY1kL+H_ncTuXD zJFr)82bdm)`g$r`9#F4#Ia|BFYoRg{GW*GQGVPrGeQM);ZDnRk`v$vV3hPsX3%ou2 zm{-=Y%c^2Vxs^?mFL0T^5b>+Vd`}%JxYT-A%It@u`$TQIkjaTqXiG==#b{aHCoB1y z4syHrM)OMGu~AbtUS?SZpQ}T8{MFi0rC)Q3+>M=apz2ChI7UO~FWE1fYgAI4rBjpJ<3c@_NM#T=i?PGJ`ux1(a zRj|q8d4#le`JbqS&ez;^`>6Cn)u}wiT#9$shn#QpIHJG!X zT51?f+OZpFBK&fbIoow8F#9;;`*I7$?LL-PdYaF9xq~Qm!?b3fmO5YV>k_)ptdySD z)?XglX1gyul^X478*;|ZkS_0&yp-vi2nI)kcU%n>P3hsUdlS~KE3W;p*x^+-_9wU7 zGbs@h>JRM)zPE+mPaQGC&uiOVkLMp>f)D-wMA`;QdrtYcO$L@&Me@LZOMdYGT}eCq z{PXjlqri|vBLsAo1LfvG`gN0=9?j%F#jzD5$ zufFXE13;iJ*1;Xc4x-Ybax(s{gCMh#P?bo922iMxd6-rkXPg;G$I6d!CG1v0$Yji3 zOgxr2mP&-mf#S@DDwdRFcQ8VDD}yg$Wuo;d(S@4_ zmL_1a8+sLD>$V%8T_#s{Pc{{at!wR|;coGsHq;oPk*GE0%~`m!pBJjt5m`nE!ZP)pTKlnjGaE%&{& zbhq?#L0kvfbW}lyL+%WIka0k}<8n~O0eVu}QW9ZN8gG-POgb@Ue=u;;driSc%Csh?};Jr zgH+z!31V+no(5yCc4DrVQ~pM;Kt1SHA7+z@ENve3@_+>CM9SSC};Cm?;7l=g0nm=FWB5#}=Kbq4a zM39+Oguq|uj)2m&>P?0zpg!V_$yzi%=*`&?r{GkazYKo!gvbN)melo^@+pzYE&+Cw z$ghaUd=K9w3%l$i>bnd_EW`jlB`m)T+>h_88n z>7bzZDSQt@7I{Kp7tSOgMPc;u>S8Iv#4F0SDpag1%+f0VE+ZU*=|$#Kj+a!7nhgPA zR+x|!`oJJ}mJq|8azgrwkNjX`HE;$jPaPgqxctk!Bs#7LW`+rM_vbOZJ{E>dR0v4r zeR?vi$TrK&u5hk{?te4eSj}r-HCtS*bm^<4V)dvz`8fJ$g%lEzV`Da)B{;2XHmD2r zLbc=`sU(MGO%vyAW@D7Bp~O-s<_Q_3LrvSCP_icoD#lG8Kv>^_RV*Wn1UFSomRZKZ zwQr@e=qhS))5XG0YIihi;s$Sn;l5D4l8b zM5cIDY_$jxoLKlZ&zc(Oa>=Nl8s?8Z8X57GvJ_Y=YZNh<_bEOyRp!fhN44J7f3J8; z$yda2+9*s3B+02`#BY3RmyK?y5r+pg6%I9a_#`9C#l06I%8yp_kd?S5mAixzb3$Xi zvmG4p8>;I`C3Un62T9`|^qq;x#dVS*2gyMKb#rDEvMsf|{Y^bYiC&ejntcee7!w^2 zDPQQ#I`}m{+q88lH_|E)-SlAy}ZXRpUo;I3=0{Gs|amftoHV z2iVx-4m%l^bKLDB`re%}(aFCjh#k0|WX&L7B$O||5(uV%JZhA*gmmzgC*yzq%kx+YYMBps|;(ducm#X zN7cLO41sx+2KbW=t7{U8c4|m}YQ%49EO%<6Yiep^YUcOU9M$x^==7rg^pfB7${9Px zzhFxQfDWL5U;zO93$_R#Pl+H0apQ#^=KT+BfiTWeVuQRmBP|^M16y+E;u}p_NA1I< zK9>H4Eo+G@#l-t({GM~wUh?^tvtu_ylNXpkSeu{Xr}c$9Dc?)#AMhY`PmouzUxdF? za7-*qXhK*}WQt)xTt+5NVop+EYJp>PREzo|PJ#AM~DDnqHinTi952UEUG=y0*T#*}HoJK-xNpJ-j-G zoqRpNaJhPXu)Y05`~1`RWPxdRThs~x1&1Co1r|d95MJoE)qw{C_UTCq$G*Y$z62uk zA@0iX?qw!0FJ}?yl+(*5u>7evvzhua8O|dnQ4-Z(rjRN0>f(T`d42w|^KZT2Cy6R*~7_qd0?ve(WvOTl5bdtk3_GLVGX+G(=uM@UM4bFlka zGnke6aP#H#Cv43#1g)1NSJSa#$nBZ8CsP3DpgWn#$W8vRVP`7)nzMWF@!js68Lk#f z9vL4jrdXpc{Osv|dxhF^;iE%mJ>F)9-Om>hf?pTIgIN2Vw!hm-4ze{S9jS8#?wZnE z)oSB^`eO7B zEQwf+3uo$dkoBVkK;0v15W_g1))G%H8zbng4P*VGlm)a+BG+|5wLFAFJj;sQTvO08 zCUE8xAmub^$+$2GS=Z3{nP+XRaPCideu)n)1qJ@P$y0Q3Hj7Da`B0x=7CCvcE_SI? z^++CctY;mRaX8wN9MCZjQ=VjFyc70uz-=YIH>f z+av|b%Q@svn66uYTnDakaK~j5)|Af)dt)RYB~t`(_j+Ho+n4<&Oo z?>DHx7~$caUnytBRh>HTefpPPW6eI-5MHd{JNLgT7*{7D<*KUsoadHX+f4UJcQZ~g z9&|GSr2m&58UN}L2Dtct^!OKk`qF}!{(+y&XgG*FJvM*g=ZA)`HAo(paB+M{GuvUv zSjjvZuW-yH#0}d2p;iRyQQ2(TD_rBXaT_u#-QdGP1>RO}@%zX#c*)ses6?{|xA6@z z^$!X+0Y#}fM#OPPCw_{JPZdqd;7dtM%gkfS&dJFyrVc19FR35}mqVbnxM9_e33V-1 zP1P-RW$o>q72Q3(eVGk|W9h@uZR10eA=5LnbFT9Xi{EXRS60{bH#WDnWA+Zc4-Ae@ zPt=f4ug+Dj?rvlU?lvF9cOS=|Eq*^DX-k5|LwK*q`6BSX^oGq)WCyh=@4bp9=79F0 ztHAeB!>CrhyRJCRN0W%fvx%a3CC1a3^gb$Mq?F2|z8Bguzv3=$%fqyOYKpq~p&Ts` zM$G_qu8>XrkjHxmQD;>P(bUrA%O)-!f*6z&R8c(Gb~JF~7k!6%RL_Jv{=py%ONk%rM9KBA!V;KYIz_C{+@>G6i)Dp#z4 zN%6_;V8PAEh|sw+-(;kFve3eyD^qQ4`f^p>@B_K@$tJEakzqiQ*!4MEN3j@j_HX!~ zFNjk92&OJ5K`0c~pM5d5GQNQN4uWVxi`)8kJP?%86#!JW=-3f7KImAH^wAK^D2D7~ zjA&+PBt{H-2N^~z&x9a)9QRrqT09?25G_IQX$&>-6Q&Sqk|@PEO0qa>1xkv7FgZ%< zXJ7?#nv8A~a=MP~2~viSBQ zfl%Q8WP<=U$J9kA45OexD6(e7L@16Eo&c2C1EGLYC*5e9vS>%3Re8P()C%JDBx_sY zl0RVug%+_|Rt9BboI(v}C@RxiwqWKpO~CQfa?Kaavzh@-3j6vf>KOa{s|n6^#+sRr z>-J3sigFIgbB1~r)oYG+4z2Gku^bcj;wdj$4=sP$b{suTIL4gzP|~&Dc#wVVZdj`1 z?7o3kT=x8EIIZnL`kBMkgVuY>*pGpwUpIg&;#WIFSl(IJ|4NUlzMa%e|GKS8qKjwj zEr^nL_>HG;!w5s=2G1miQ77*>m#b*w`1=K_cg-F?x%HDm`&4{$A|fKJ6JmDjjbmT9 zeEFsn-gfdW%1(+lPYba5H_u7x=$25!sxT|@f0 zWyx&+PxGcHXtQO}KPInr2Xt%Dw(FbYV1@X<4G1G30$>4Sb%hceVa|q4>4yH5 z@2mYW&0FkhjmD9)Y7t`ijI{gBYvft!pA-SsL8OKu4x#v*5uhmCSm*dx;fWr}8fi(% zS>Eyfxjv!bfS}akIM?zJ*D@$XKc=R{q#;(npgCKuJyET?t3$Rg4cI%_|8X?y^T@=Q z-OP~C^f!BKonfc9OM)9enXVt6(*>OV zNV+(H(|q0`Q=IKO7UCfa%?SAgU#$;Oh;iOPm?h!61F;lFckf7D#+s6;X&5CRKVi$! zu?tNkdL@wqvv>_(u72TKVdv3EKKX$f#uSPfG@f?aacyKu*(6C!guj}9s`zZp*_2&d z!d+0%U^dZC@v?8 z^_B}$hJcWw6yM}}wFpO7Lv>M*!-8oYl`es~GFG-)xk*Q`WX)fc;~G?LcN; zU4T}HnL~HHO(k&;_rq-e(5s@6>yGu5!C>%?f)Pp}d(rGI$9pl{BP)A^yi3;malG@9`|+Yn z5VHhv)T})s36jVnQH4`P*bgDIxk4RZVh0swQicMY^oxcxj?x0ET&{>5YtK zmWXOpS(0rHhGmW;HHKBLCF`f79N7)>gIu3AFUtbX8;s)=51i;?a5!qTbrCz~1SC5C zqmM;lGJ)>rQn|yZlb9qR@TBaWEv7A`D86H_yiC#C23lT}4XrF2pg4tAN$9dxHpKg| z)pX7P?W$7<5UQ#Na4KQABd9U<4ePy#>!+2&6zlfYvrjO|h6%$-`=&ufIgZwu5XzdC zbxu7;oE6I$$&S4Mxr_GGhUc25!vPV=4%kG{*B+i7z1r@lrt3i5u_WFJzEx+2)w=w#>Em#T9^_?t|>oqmsO`oia)Z0W| z3rvD+N6H-4g(J#6xq*>|QP`{)GZ`D+)OjcE6OIwx{$=`1f33kTSCI>U|D+>emUid6o?nP>pp7{w(lN|CD$Xj#G(OqLDN#u^B}?5i zT{xrDuSyPb712jB;4GV0@-y zl5l2$H1`|P;^Hz#%j)1d$JY4V4$j`#(huCtqt;>=*Lly?{7v^A!P!IQ!LR3wUv$4a ziSa^ug29*);$y4^pTet%gay%6l0Ul=OWqfIvcvaFJV|rB-Q4Q?WfU05l|{!#cO}zF z)DVNn-<8T_`|{5ZW}zPpr->4e=aQ=@Dtf(+nZNc{VJRpCBnvyZs&7tLSY`r;bkSfM zHHP{<$m^)A$_*M|f-iPb_IUE_tM3l&8q#3cIe%PJOAr{YdWGkWGKJ1{cojoFQ|cDm%ir z)p|>oYu%sh<0<^^uJ(97MtsIG6LdagOce-o91wDXk(S6!#eE37y`ax^Mcv-z?>Su= zb}e_z=k?z0+6GzUD!!l(JxF$GX25%n;Ji*R7WMCkp{Zbjga`ox46OhVBI<|ngdE_%ldV=iVE zWMwH~kg+`}Obu~5Db4b!J1Nhzy*hzpdH`7~%JO|!OQ0>f(7c)vOuMS47TMG4TF0o< z8p8{iU5(@mt9|kSNu^c%2qRWi1bl)&#Nu|&EP0B)w{j^U_TGMozPlnr9f@2j8dq!HP=kY)>+E+7`ZRL z2-y5;YkDNtveNBupuaSwpkT1DN1$LhcXOU=G!5vf0*~W|RP7GaI_ejVa)rm9jrT)0 z4!S#f`#dmWxK`{(Uis27E)1LNNVrI+#Nc zFZ$Os;^P8e?*E-eq-?p@T#CNA>&S6J`DYp-ZJgzYQ4mt*2DIR)?S&nWmsyr)r_a^TA_0@VsGGa!JH9ndBYmH?(TDM4uXdAR`PZ z&a28UL`~+Dn@;$BYCK9K5d`%tw!4PT7KEC-6T}3X8|$4;f>WDV7U!Z}LHG7Ma)Js5pMnXk29(>b z--Oc;%aJgQ*8kwNWVFK}-fcKy$`XkANWa^7f>9`4$vL>wbh=n+#znUC#CNt*Ns0&g z^T_Y`z1myv;g2sL62br_Ay-d3!uf$;#=8t`geSw31tdLj$JZPWXJ6l)U0mFYcr{S9 zr5M@1h%VyJE~7bIZZXL{3Z5)$$x3{9iHAR(M|{KB|1+u*gh;n2;fIPDY8-MmHV2l# zl@P>vg{|nN7)Cmon1tTbqt&(*%jf>id zd`m`t6B(XBU$a}3D1m2VLM4O4f*SvA2j4sexFkK6DyoT*&mi3cVQ_`IRqST8-P4r? znSc5nvkMwzcsfxV=<%^KnmhzWlA2feB{)8&c(7q1 z6!-9!x2^cuy=~e6>*2L`p$<6KUzj#S@~D<_*t(?W%P)IT`sAqk{*A)q5abZf{>O#? zcXwn*((#|&5xL_(C@d%2i9N^h@9t=3+7I{i@9t>jiag;>k;}LrZ9(^6adAl0)Q){&3Pz5bMy4(x+fK4MuWQ$_TyOmgW=IK)VVBg`X}5Rx2|pbl zpPv83JX|Ab%NPSf!jb9NAx^Y3Ae=|>*fuM=FCrvd1LKfu_^Z))Yiw%dlX}|mk8hMP zffWtWW9hUy1Lk)whrkqmgQckoHO5&^k-+&o7NW?pq%S#C3Q#we1qQ_esc2RW^zTrq zTGMG~q7%&;-QJ~Rmv6{l&X0C=fHlD+W z%VD+U>;6bZ=R@aK))4}3fa9-F_YoE%r2s!l*U8y@$v2Ff0}Zg03bWQ4JCOs8EsbDY z_#cADp2OLguO$IU&kq-W`rhbUe*7c*pfWd(+x8Lu0{`{L(})NWdjC1tH7bOLxt@KD z1{WuvK{C{dM{-wNOkbN;kfLSSB!YSXsfdB@g&~Mt79F)Onz<%@3BWcYXo|zLgx(kX zzR%h$POwJ2FJAm1G6Wz_!a|QKMpAK*M2uH)kRmU&bC9AgwHg$!Zs}c|CTn|Qk*enN zXpvwN&2kuPk!@ocVFRsT40Gr>ISg^0U?~rBU$ZIqM?R=1&p&s6JOWFFM=%sdqUsnF zMDcgfyG97JR>TeR2%nTj&y%o}{)`NZDHxLX+AJ$h)xHrGOVYRwW=xp z={q1`30kR+JOw?iO?^3FtsAmkRjq9&sXU8^lhWp#HOyH?D>p5^oG3T1YzaBEY~;%- zx9(72DYqR+tSYr11J@Nh&Th1oI;-E6+AWs`Hz5klx0gb%fY=gJqO8DwbvJbq@Q95~~1^M~Qaabffz{?V zhZDa!815@@y$S1P72msxdioW~BxwjPru5JgIzG_k1t0FmzLRA*&NJG%10aPO3M2pf zy!eI?3a|pG{5PfJh2#CRQ~YrBV$2N86Uet-OU;AzywMwQJ0Gj69&GD^ms8`&9H9FT zoBvo*6V{qKTp%Y_O#8l{mTBSWxp~}5LXu$g1E!NUQv-6i7a_WwF>`-@oq~JG2n&h8igJiSiF1xfN)AkQ_sz(3&G!D9=WhirG%60(D=Sy42ve%6)~>D7Z-{DY zZWL}yGVYA)?rGug@9h|B=Np9%PLxbdr;W_T_bmi`U-Fq>brjoJUf(v{+H+a?A$f4D z3p+hIy5JDMRz1ICeE3Op`*id8v-OGi`wwoUL=QSZj*=RT%XY-SO zrZap~D&`H3B9YLI@mK`Y`?5Q-m;*644wafvp++j=3@(QyB2Tr$FXip1F(w$cq2)d3ny8mHQhCYwFOYb3{O zX3pnZuhN&#bc)^GQ8h(8b&dKpc5$R~$gWIBZOAY0-7~L@I+BRR)~4DUk7mJ=G1Lkj zO(zQwwMxV3j^@+lIO5)AC;pADfI^UAgG<4Zoi?16TZL!O9J8n2qY_8L5g)&J0U;DM|VK5KWMw506ZC5 z(2J1sE{L45a3>sv4l?9NLt$+ag^(Xf7pR0+XBzaHtoLyh5|V7i##xqn`Sxy4o!T>omS1vev`18 zgM8x)-0hI(fhN}%pk$|*`7>+X-NVE=&V#KTs4W`i>i{_~!$RyDThpl!K`=uJ7w~#H#Km&B(Pcrs@^1ET4w19FkxxY%osHWjsn{ zanw>V%rL46p{ITD9p8Tobm2GuX7u|PdHfAsH{G07)nCwA<}h|QN2vN|G_>*qnY#^^ z4~KhnZQ(1*K)slrRUXHH66_cFijd4Jx$w@(4d_E%#>fvrtD(6Xl;`PXy+K;-`b DwI{5l diff --git a/src/bower_components/emby-webcomponents/loading/loading-legacy.css b/src/bower_components/emby-webcomponents/loading/loading-legacy.css index af2627b988..17ea94950e 100644 --- a/src/bower_components/emby-webcomponents/loading/loading-legacy.css +++ b/src/bower_components/emby-webcomponents/loading/loading-legacy.css @@ -6,5 +6,5 @@ position: fixed; top: 50%; left: 50%; - z-index: 9999999 -} \ No newline at end of file + z-index: 9999999; +} diff --git a/src/bower_components/emby-webcomponents/loading/loading-legacy.js b/src/bower_components/emby-webcomponents/loading/loading-legacy.js index cd6620558f..bb8d8a99ab 100644 --- a/src/bower_components/emby-webcomponents/loading/loading-legacy.js +++ b/src/bower_components/emby-webcomponents/loading/loading-legacy.js @@ -1,14 +1,33 @@ -define(["require", "css!./loading-legacy"], function(require) { - "use strict"; +define(['require', 'css!./loading-legacy'], function (require) { + 'use strict'; + var loadingElem; + return { - show: function() { + show: function () { var elem = loadingElem; - elem || (elem = document.createElement("img"), elem.src = require.toUrl(".").split("?")[0] + "/loader2.gif", loadingElem = elem, elem.classList.add("loading-spinner"), document.body.appendChild(elem)), elem.classList.remove("hide") + + if (!elem) { + + elem = document.createElement("img"); + elem.src = require.toUrl('.').split('?')[0] + '/loader2.gif'; + + loadingElem = elem; + + elem.classList.add('loading-spinner'); + + document.body.appendChild(elem); + } + + elem.classList.remove('hide'); }, - hide: function() { + hide: function () { var elem = loadingElem; - elem && elem.classList.add("hide") + + if (elem) { + + elem.classList.add('hide'); + } } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/loading/loading-lite.css b/src/bower_components/emby-webcomponents/loading/loading-lite.css index d70b2969a8..6d8472fc15 100644 --- a/src/bower_components/emby-webcomponents/loading/loading-lite.css +++ b/src/bower_components/emby-webcomponents/loading/loading-lite.css @@ -2,26 +2,26 @@ position: relative; width: 1.95em; height: 1.95em; - display: none + display: none; } .mdlSpinnerActive { display: inline-block; - -webkit-animation: mdl-spinner__container-rotate 1.568s linear infinite; - animation: mdl-spinner__container-rotate 1.568s linear infinite + -webkit-animation: mdl-spinner__container-rotate 1568.23529412ms linear infinite; + animation: mdl-spinner__container-rotate 1568.23529412ms linear infinite; } @-webkit-keyframes mdl-spinner__container-rotate { to { -webkit-transform: rotate(360deg); - transform: rotate(360deg) + transform: rotate(360deg); } } @keyframes mdl-spinner__container-rotate { to { -webkit-transform: rotate(360deg); - transform: rotate(360deg) + transform: rotate(360deg); } } @@ -29,240 +29,319 @@ position: absolute; width: 100%; height: 100%; - opacity: 0 + opacity: 0; } .mdl-spinner__layer-1 { - border-color: #42a5f5 + border-color: rgb(66,165,245); } .mdl-spinner__layer-1-active { - -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4, 0, .2, 1) infinite both, mdl-spinner__layer-1-fade-in-out 5332ms cubic-bezier(.4, 0, .2, 1) infinite both; - animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4, 0, .2, 1) infinite both, mdl-spinner__layer-1-fade-in-out 5332ms cubic-bezier(.4, 0, .2, 1) infinite both + -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-1-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-1-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } .mdl-spinner__layer-2 { - border-color: #f44336 + border-color: rgb(244,67,54); } .mdl-spinner__layer-2-active { - -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4, 0, .2, 1) infinite both, mdl-spinner__layer-2-fade-in-out 5332ms cubic-bezier(.4, 0, .2, 1) infinite both; - animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4, 0, .2, 1) infinite both, mdl-spinner__layer-2-fade-in-out 5332ms cubic-bezier(.4, 0, .2, 1) infinite both + -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-2-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-2-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } .mdl-spinner__layer-3 { - border-color: #fdd835 + border-color: rgb(253,216,53); } .mdl-spinner__layer-3-active { - -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4, 0, .2, 1) infinite both, mdl-spinner__layer-3-fade-in-out 5332ms cubic-bezier(.4, 0, .2, 1) infinite both; - animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4, 0, .2, 1) infinite both, mdl-spinner__layer-3-fade-in-out 5332ms cubic-bezier(.4, 0, .2, 1) infinite both + -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-3-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-3-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } .mdl-spinner__layer-4 { - border-color: #4caf50 + border-color: rgb(76,175,80); } .mdl-spinner__layer-4-active { - -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4, 0, .2, 1) infinite both, mdl-spinner__layer-4-fade-in-out 5332ms cubic-bezier(.4, 0, .2, 1) infinite both; - animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4, 0, .2, 1) infinite both, mdl-spinner__layer-4-fade-in-out 5332ms cubic-bezier(.4, 0, .2, 1) infinite both + -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-4-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-4-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } @-webkit-keyframes mdl-spinner__fill-unfill-rotate { 12.5% { -webkit-transform: rotate(135deg); - transform: rotate(135deg) + transform: rotate(135deg); } 25% { -webkit-transform: rotate(270deg); - transform: rotate(270deg) + transform: rotate(270deg); } 37.5% { -webkit-transform: rotate(405deg); - transform: rotate(405deg) + transform: rotate(405deg); } 50% { -webkit-transform: rotate(540deg); - transform: rotate(540deg) + transform: rotate(540deg); } 62.5% { -webkit-transform: rotate(675deg); - transform: rotate(675deg) + transform: rotate(675deg); } 75% { -webkit-transform: rotate(810deg); - transform: rotate(810deg) + transform: rotate(810deg); } 87.5% { -webkit-transform: rotate(945deg); - transform: rotate(945deg) + transform: rotate(945deg); } to { -webkit-transform: rotate(1080deg); - transform: rotate(1080deg) + transform: rotate(1080deg); } } @keyframes mdl-spinner__fill-unfill-rotate { 12.5% { -webkit-transform: rotate(135deg); - transform: rotate(135deg) + transform: rotate(135deg); } 25% { -webkit-transform: rotate(270deg); - transform: rotate(270deg) + transform: rotate(270deg); } 37.5% { -webkit-transform: rotate(405deg); - transform: rotate(405deg) + transform: rotate(405deg); } 50% { -webkit-transform: rotate(540deg); - transform: rotate(540deg) + transform: rotate(540deg); } 62.5% { -webkit-transform: rotate(675deg); - transform: rotate(675deg) + transform: rotate(675deg); } 75% { -webkit-transform: rotate(810deg); - transform: rotate(810deg) + transform: rotate(810deg); } 87.5% { -webkit-transform: rotate(945deg); - transform: rotate(945deg) + transform: rotate(945deg); } to { -webkit-transform: rotate(1080deg); - transform: rotate(1080deg) + transform: rotate(1080deg); } } +/** +* HACK: Even though the intention is to have the current .mdl-spinner__layer-N +* at `opacity: 1`, we set it to `opacity: 0.99` instead since this forces Chrome +* to do proper subpixel rendering for the elements being animated. This is +* especially visible in Chrome 39 on Ubuntu 14.04. See: +* +* - https://github.com/Polymer/paper-spinner/issues/9 +* - https://code.google.com/p/chromium/issues/detail?id=436255 +*/ @-webkit-keyframes mdl-spinner__layer-1-fade-in-out { - - 100%, - 25%, - 90%, from { - opacity: .99 + opacity: 0.99; + } + + 25% { + opacity: 0.99; + } + + 26% { + opacity: 0; } - 26%, 89% { - opacity: 0 + opacity: 0; + } + + 90% { + opacity: 0.99; + } + + 100% { + opacity: 0.99; } } @keyframes mdl-spinner__layer-1-fade-in-out { - - 100%, - 25%, - 90%, from { - opacity: .99 + opacity: 0.99; + } + + 25% { + opacity: 0.99; + } + + 26% { + opacity: 0; } - 26%, 89% { - opacity: 0 + opacity: 0; + } + + 90% { + opacity: 0.99; + } + + 100% { + opacity: 0.99; } } @-webkit-keyframes mdl-spinner__layer-2-fade-in-out { - - 15%, - 51%, from { - opacity: 0 + opacity: 0; + } + + 15% { + opacity: 0; + } + + 25% { + opacity: 0.99; } - 25%, 50% { - opacity: .99 + opacity: 0.99; + } + + 51% { + opacity: 0; } } @keyframes mdl-spinner__layer-2-fade-in-out { - - 15%, - 51%, from { - opacity: 0 + opacity: 0; + } + + 15% { + opacity: 0; + } + + 25% { + opacity: 0.99; } - 25%, 50% { - opacity: .99 + opacity: 0.99; + } + + 51% { + opacity: 0; } } @-webkit-keyframes mdl-spinner__layer-3-fade-in-out { - - 40%, - 76%, from { - opacity: 0 + opacity: 0; + } + + 40% { + opacity: 0; + } + + 50% { + opacity: 0.99; } - 50%, 75% { - opacity: .99 + opacity: 0.99; + } + + 76% { + opacity: 0; } } @keyframes mdl-spinner__layer-3-fade-in-out { - - 40%, - 76%, from { - opacity: 0 + opacity: 0; + } + + 40% { + opacity: 0; + } + + 50% { + opacity: 0.99; } - 50%, 75% { - opacity: .99 + opacity: 0.99; + } + + 76% { + opacity: 0; } } @-webkit-keyframes mdl-spinner__layer-4-fade-in-out { - - 100%, - 65%, from { - opacity: 0 + opacity: 0; + } + + 65% { + opacity: 0; + } + + 75% { + opacity: 0.99; } - 75%, 90% { - opacity: .99 + opacity: 0.99; + } + + 100% { + opacity: 0; } } @keyframes mdl-spinner__layer-4-fade-in-out { - - 100%, - 65%, from { - opacity: 0 + opacity: 0; + } + + 65% { + opacity: 0; + } + + 75% { + opacity: 0.99; } - 75%, 90% { - opacity: .99 + opacity: 0.99; + } + + 100% { + opacity: 0; } } @@ -272,22 +351,20 @@ width: 50%; height: 100%; overflow: hidden; - border-color: inherit + border-color: inherit; } -.mdl-spinner__circle-clipper .mdl-spinner__circle { - width: 200% -} + .mdl-spinner__circle-clipper .mdl-spinner__circle { + width: 200%; + } .mdl-spinner__circle { - -webkit-box-sizing: border-box; box-sizing: border-box; height: 100%; border-width: .21em; border-style: solid; border-color: inherit; border-bottom-color: transparent !important; - -webkit-border-radius: 50%; border-radius: 50%; -webkit-animation: none; animation: none; @@ -295,85 +372,97 @@ top: 0; right: 0; bottom: 0; - left: 0 + left: 0; } .mdl-spinner__circleLeft { border-right-color: transparent !important; -webkit-transform: rotate(129deg); - transform: rotate(129deg) + transform: rotate(129deg); } .mdl-spinner__circleLeft-active { - -webkit-animation: mdl-spinner__left-spin 1333ms cubic-bezier(.4, 0, .2, 1) infinite both; - animation: mdl-spinner__left-spin 1333ms cubic-bezier(.4, 0, .2, 1) infinite both + -webkit-animation: mdl-spinner__left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } .mdl-spinner__circleRight { left: -100%; border-left-color: transparent !important; -webkit-transform: rotate(-129deg); - transform: rotate(-129deg) + transform: rotate(-129deg); } .mdl-spinner__circleRight-active { - -webkit-animation: mdl-spinner__right-spin 1333ms cubic-bezier(.4, 0, .2, 1) infinite both; - animation: mdl-spinner__right-spin 1333ms cubic-bezier(.4, 0, .2, 1) infinite both + -webkit-animation: mdl-spinner__right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } @-webkit-keyframes mdl-spinner__left-spin { - - from, - to { + from { -webkit-transform: rotate(130deg); - transform: rotate(130deg) + transform: rotate(130deg); } 50% { -webkit-transform: rotate(-5deg); - transform: rotate(-5deg) + transform: rotate(-5deg); + } + + to { + -webkit-transform: rotate(130deg); + transform: rotate(130deg); } } @keyframes mdl-spinner__left-spin { - - from, - to { + from { -webkit-transform: rotate(130deg); - transform: rotate(130deg) + transform: rotate(130deg); } 50% { -webkit-transform: rotate(-5deg); - transform: rotate(-5deg) + transform: rotate(-5deg); + } + + to { + -webkit-transform: rotate(130deg); + transform: rotate(130deg); } } @-webkit-keyframes mdl-spinner__right-spin { - - from, - to { + from { -webkit-transform: rotate(-130deg); - transform: rotate(-130deg) + transform: rotate(-130deg); } 50% { -webkit-transform: rotate(5deg); - transform: rotate(5deg) + transform: rotate(5deg); + } + + to { + -webkit-transform: rotate(-130deg); + transform: rotate(-130deg); } } @keyframes mdl-spinner__right-spin { - - from, - to { + from { -webkit-transform: rotate(-130deg); - transform: rotate(-130deg) + transform: rotate(-130deg); } 50% { -webkit-transform: rotate(5deg); - transform: rotate(5deg) + transform: rotate(5deg); + } + + to { + -webkit-transform: rotate(-130deg); + transform: rotate(-130deg); } } @@ -386,5 +475,5 @@ top: 50%; left: 50%; z-index: 9999999; - contain: layout style size -} \ No newline at end of file + contain: layout style size; +} diff --git a/src/bower_components/emby-webcomponents/loading/loading-lite.js b/src/bower_components/emby-webcomponents/loading/loading-lite.js index ecdfb255d8..00aff8f0f8 100644 --- a/src/bower_components/emby-webcomponents/loading/loading-lite.js +++ b/src/bower_components/emby-webcomponents/loading/loading-lite.js @@ -1,22 +1,78 @@ -define(["css!./loading-lite"], function() { - "use strict"; - var loadingElem, layer1, layer2, layer3, layer4, circleLefts, circleRights; +define(['css!./loading-lite'], function () { + 'use strict'; + + var loadingElem; + var layer1; + var layer2; + var layer3; + var layer4; + var circleLefts; + var circleRights; + return { - show: function() { + show: function () { var elem = loadingElem; - elem || (elem = document.createElement("div"), loadingElem = elem, elem.classList.add("docspinner"), elem.classList.add("mdl-spinner"), elem.innerHTML = '
', document.body.appendChild(elem), layer1 = elem.querySelector(".mdl-spinner__layer-1"), layer2 = elem.querySelector(".mdl-spinner__layer-2"), layer3 = elem.querySelector(".mdl-spinner__layer-3"), layer4 = elem.querySelector(".mdl-spinner__layer-4"), circleLefts = elem.querySelectorAll(".mdl-spinner__circleLeft"), circleRights = elem.querySelectorAll(".mdl-spinner__circleRight")), elem.classList.add("mdlSpinnerActive"), layer1.classList.add("mdl-spinner__layer-1-active"), layer2.classList.add("mdl-spinner__layer-2-active"), layer3.classList.add("mdl-spinner__layer-3-active"), layer4.classList.add("mdl-spinner__layer-4-active"); + + if (!elem) { + + elem = document.createElement("div"); + loadingElem = elem; + + elem.classList.add('docspinner'); + elem.classList.add('mdl-spinner'); + + elem.innerHTML = '
'; + + document.body.appendChild(elem); + + layer1 = elem.querySelector('.mdl-spinner__layer-1'); + layer2 = elem.querySelector('.mdl-spinner__layer-2'); + layer3 = elem.querySelector('.mdl-spinner__layer-3'); + layer4 = elem.querySelector('.mdl-spinner__layer-4'); + + circleLefts = elem.querySelectorAll('.mdl-spinner__circleLeft'); + circleRights = elem.querySelectorAll('.mdl-spinner__circleRight'); + } + + elem.classList.add('mdlSpinnerActive'); + + layer1.classList.add('mdl-spinner__layer-1-active'); + layer2.classList.add('mdl-spinner__layer-2-active'); + layer3.classList.add('mdl-spinner__layer-3-active'); + layer4.classList.add('mdl-spinner__layer-4-active'); + var i, length; - for (i = 0, length = circleLefts.length; i < length; i++) circleLefts[i].classList.add("mdl-spinner__circleLeft-active"); - for (i = 0, length = circleRights.length; i < length; i++) circleRights[i].classList.add("mdl-spinner__circleRight-active") + + for (i = 0, length = circleLefts.length; i < length; i++) { + circleLefts[i].classList.add('mdl-spinner__circleLeft-active'); + } + + for (i = 0, length = circleRights.length; i < length; i++) { + circleRights[i].classList.add('mdl-spinner__circleRight-active'); + } }, - hide: function() { + hide: function () { var elem = loadingElem; + if (elem) { - elem.classList.remove("mdlSpinnerActive"), elem.classList.remove("mdl-spinner__layer-1-active"), elem.classList.remove("mdl-spinner__layer-2-active"), elem.classList.remove("mdl-spinner__layer-3-active"), elem.classList.remove("mdl-spinner__layer-4-active"); + + elem.classList.remove('mdlSpinnerActive'); + + elem.classList.remove('mdl-spinner__layer-1-active'); + elem.classList.remove('mdl-spinner__layer-2-active'); + elem.classList.remove('mdl-spinner__layer-3-active'); + elem.classList.remove('mdl-spinner__layer-4-active'); + var i, length; - for (i = 0, length = circleLefts.length; i < length; i++) circleLefts[i].classList.remove("mdl-spinner__circleLeft-active"); - for (i = 0, length = circleRights.length; i < length; i++) circleRights[i].classList.remove("mdl-spinner__circleRight-active") + + for (i = 0, length = circleLefts.length; i < length; i++) { + circleLefts[i].classList.remove('mdl-spinner__circleLeft-active'); + } + + for (i = 0, length = circleRights.length; i < length; i++) { + circleRights[i].classList.remove('mdl-spinner__circleRight-active'); + } } } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/loadingdialog/loadingdialog.js b/src/bower_components/emby-webcomponents/loadingdialog/loadingdialog.js index 63694066e4..5f176399db 100644 --- a/src/bower_components/emby-webcomponents/loadingdialog/loadingdialog.js +++ b/src/bower_components/emby-webcomponents/loadingdialog/loadingdialog.js @@ -1,34 +1,101 @@ -define(["loading", "events", "dialogHelper", "dom", "layoutManager", "scrollHelper", "globalize", "require", "material-icons", "emby-button", "paper-icon-button-light", "emby-input", "formDialogStyle", "flexStyles"], function(loading, events, dialogHelper, dom, layoutManager, scrollHelper, globalize, require) { - "use strict"; +define(['loading', 'events', 'dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (loading, events, dialogHelper, dom, layoutManager, scrollHelper, globalize, require) { + 'use strict'; function showDialog(instance, options, template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 - }, - enableTvLayout = layoutManager.tv; - enableTvLayout && (dialogOptions.size = "fullscreen"); + removeOnClose: true, + scrollY: false + }; + + var enableTvLayout = layoutManager.tv; + + if (enableTvLayout) { + dialogOptions.size = 'fullscreen'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateHtml(template, "sharedcomponents"), dlg.classList.add("align-items-center"), dlg.classList.add("justify-items-center"); - var formDialogContent = dlg.querySelector(".formDialogContent"); - return formDialogContent.style["flex-grow"] = "initial", formDialogContent.style["max-width"] = "50%", formDialogContent.style["max-height"] = "60%", enableTvLayout ? (scrollHelper.centerFocus.on(formDialogContent, !1), dlg.querySelector(".formDialogHeader").style.marginTop = "15%") : dlg.classList.add("dialog-fullscreen-lowres"), dlg.querySelector(".formDialogHeaderTitle").innerHTML = options.title, dlg.querySelector(".text").innerHTML = options.text, instance.dlg = dlg, dialogHelper.open(dlg).then(function() { - enableTvLayout && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), loading.hide() - }) + + var configuredButtons = []; + + dlg.classList.add('formDialog'); + + dlg.innerHTML = globalize.translateHtml(template, 'sharedcomponents'); + + dlg.classList.add('align-items-center'); + dlg.classList.add('justify-items-center'); + + var formDialogContent = dlg.querySelector('.formDialogContent'); + formDialogContent.style['flex-grow'] = 'initial'; + formDialogContent.style['max-width'] = '50%'; + formDialogContent.style['max-height'] = '60%'; + + if (enableTvLayout) { + scrollHelper.centerFocus.on(formDialogContent, false); + dlg.querySelector('.formDialogHeader').style.marginTop = '15%'; + } else { + dlg.classList.add('dialog-fullscreen-lowres'); + } + + //dlg.querySelector('.btnCancel').addEventListener('click', function (e) { + // dialogHelper.close(dlg); + //}); + + dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title; + + dlg.querySelector('.text').innerHTML = options.text; + + instance.dlg = dlg; + + return dialogHelper.open(dlg).then(function () { + + if (enableTvLayout) { + scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); + } + + loading.hide(); + }); } function LoadingDialog(options) { - this.options = options + + this.options = options; } - return LoadingDialog.prototype.show = function() { + + LoadingDialog.prototype.show = function () { + var instance = this; - return loading.show(), new Promise(function(resolve, reject) { - require(["text!./../dialog/dialog.template.html"], function(template) { - showDialog(instance, instance.options, template), resolve() - }) - }) - }, LoadingDialog.prototype.setTitle = function(title) {}, LoadingDialog.prototype.setText = function(text) {}, LoadingDialog.prototype.hide = function() { - this.dlg && (dialogHelper.close(this.dlg), this.dlg = null) - }, LoadingDialog.prototype.destroy = function() { - this.dlg = null, this.options = null - }, LoadingDialog + loading.show(); + + return new Promise(function (resolve, reject) { + require(['text!./../dialog/dialog.template.html'], function (template) { + showDialog(instance, instance.options, template); + resolve(); + }); + }); + }; + + LoadingDialog.prototype.setTitle = function (title) { + + }; + + LoadingDialog.prototype.setText = function (text) { + + }; + + LoadingDialog.prototype.hide = function () { + + if (this.dlg) { + dialogHelper.close(this.dlg); + this.dlg = null; + } + }; + + LoadingDialog.prototype.destroy = function () { + + this.dlg = null; + this.options = null; + }; + + return LoadingDialog; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/maintabsmanager.js b/src/bower_components/emby-webcomponents/maintabsmanager.js index 2a213f31eb..07f575c11c 100644 --- a/src/bower_components/emby-webcomponents/maintabsmanager.js +++ b/src/bower_components/emby-webcomponents/maintabsmanager.js @@ -1,97 +1,267 @@ -define(["dom", "browser", "events", "emby-tabs", "emby-button", "emby-linkbutton"], function(dom, browser, events) { - "use strict"; +define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button', 'emby-linkbutton'], function (dom, browser, events) { + 'use strict'; + + var tabOwnerView; + var queryScope = document.querySelector('.skinHeader'); + var footerTabsContainer; + var headerTabsContainer; + var tabsElem; function enableTabsInFooter() { - return !1 + return false; + } + + function getTabsContainerElem() { } function ensureElements(enableInFooter) { - enableInFooter && (footerTabsContainer || (footerTabsContainer = document.createElement("div"), footerTabsContainer.classList.add("footerTabs"), footerTabsContainer.classList.add("sectionTabs"), footerTabsContainer.classList.add("hide"))), headerTabsContainer || (headerTabsContainer = queryScope.querySelector(".headerTabs")) + + if (enableInFooter) { + if (!footerTabsContainer) { + footerTabsContainer = document.createElement('div'); + footerTabsContainer.classList.add('footerTabs'); + footerTabsContainer.classList.add('sectionTabs'); + footerTabsContainer.classList.add('hide'); + //appFooter.add(footerTabsContainer); + } + } + + if (!headerTabsContainer) { + headerTabsContainer = queryScope.querySelector('.headerTabs'); + } } function onViewTabsReady() { - this.selectedIndex(this.readySelectedIndex), this.readySelectedIndex = null + this.selectedIndex(this.readySelectedIndex); + this.readySelectedIndex = null; } function allowSwipe(target) { - for (var parent = target; null != parent;) { - if (! function(elem) { - if (dom.parentWithTag(elem, "input")) return !1; - var classList = elem.classList; - return !classList || !classList.contains("scrollX") && !classList.contains("animatedScrollX") - }(parent)) return !1; - parent = parent.parentNode + + function allowSwipeOn(elem) { + + if (dom.parentWithTag(elem, 'input')) { + return false; + } + + var classList = elem.classList; + if (classList) { + return !classList.contains('scrollX') && !classList.contains('animatedScrollX'); + } + + return true; } - return !0 + + var parent = target; + while (parent != null) { + if (!allowSwipeOn(parent)) { + return false; + } + parent = parent.parentNode; + } + + return true; } function configureSwipeTabs(view, tabsElem, getTabContainersFn) { - if (browser.touch) { - var onSwipeLeft = (getTabContainersFn().length, function(e, target) { - allowSwipe(target) && view.contains(target) && tabsElem.selectNext() - }), - onSwipeRight = function(e, target) { - allowSwipe(target) && view.contains(target) && tabsElem.selectPrevious() - }; - require(["touchHelper"], function(TouchHelper) { - var touchHelper = new TouchHelper(view.parentNode.parentNode); - events.on(touchHelper, "swipeleft", onSwipeLeft), events.on(touchHelper, "swiperight", onSwipeRight), view.addEventListener("viewdestroy", function() { - touchHelper.destroy() - }) - }) + + if (!browser.touch) { + return; } + + // implement without hammer + var pageCount = getTabContainersFn().length; + var onSwipeLeft = function (e, target) { + if (allowSwipe(target) && view.contains(target)) { + tabsElem.selectNext(); + } + }; + + var onSwipeRight = function (e, target) { + if (allowSwipe(target) && view.contains(target)) { + tabsElem.selectPrevious(); + } + }; + + require(['touchHelper'], function (TouchHelper) { + + var touchHelper = new TouchHelper(view.parentNode.parentNode); + + events.on(touchHelper, 'swipeleft', onSwipeLeft); + events.on(touchHelper, 'swiperight', onSwipeRight); + + view.addEventListener('viewdestroy', function () { + touchHelper.destroy(); + }); + }); } function setTabs(view, selectedIndex, getTabsFn, getTabContainersFn, onBeforeTabChange, onTabChange, setSelectedIndex) { + var enableInFooter = enableTabsInFooter(); - if (!view) return tabOwnerView && (headerTabsContainer || (headerTabsContainer = queryScope.querySelector(".headerTabs")), ensureElements(enableInFooter), document.body.classList.remove("withSectionTabs"), headerTabsContainer.innerHTML = "", headerTabsContainer.classList.add("hide"), footerTabsContainer && (footerTabsContainer.innerHTML = "", footerTabsContainer.classList.add("hide")), tabOwnerView = null), { - tabsContainer: headerTabsContainer, - replaced: !1 - }; - ensureElements(enableInFooter); - var tabsContainerElem = enableInFooter ? footerTabsContainer : headerTabsContainer; - if (tabOwnerView || tabsContainerElem.classList.remove("hide"), tabOwnerView !== view) { - var index = 0, - indexAttribute = null == selectedIndex ? "" : ' data-index="' + selectedIndex + '"', - tabsHtml = '
' + getTabsFn().map(function(t) { - var tabClass = "emby-tab-button"; - !1 === t.enabled && (tabClass += " hide"); - var tabHtml; - return t.cssClass && (tabClass += " " + t.cssClass), tabHtml = t.href ? '
' + t.name + "
" : '", index++, tabHtml - }).join("") + "
"; - return tabsContainerElem.innerHTML = tabsHtml, document.body.classList.add("withSectionTabs"), tabOwnerView = view, tabsElem = tabsContainerElem.querySelector('[is="emby-tabs"]'), configureSwipeTabs(view, tabsElem, getTabContainersFn), tabsElem.addEventListener("beforetabchange", function(e) { - var tabContainers = getTabContainersFn(); - if (null != e.detail.previousIndex) { - var previousPanel = tabContainers[e.detail.previousIndex]; - previousPanel && previousPanel.classList.remove("is-active") + + if (!view) { + if (tabOwnerView) { + + if (!headerTabsContainer) { + headerTabsContainer = queryScope.querySelector('.headerTabs'); } + + ensureElements(enableInFooter); + + document.body.classList.remove('withSectionTabs'); + + headerTabsContainer.innerHTML = ''; + headerTabsContainer.classList.add('hide'); + + if (footerTabsContainer) { + footerTabsContainer.innerHTML = ''; + footerTabsContainer.classList.add('hide'); + } + + tabOwnerView = null; + } + return { + tabsContainer: headerTabsContainer, + replaced: false + }; + } + + ensureElements(enableInFooter); + + var tabsContainerElem = enableInFooter ? footerTabsContainer : headerTabsContainer; + + if (!tabOwnerView) { + tabsContainerElem.classList.remove('hide'); + } + + if (tabOwnerView !== view) { + + var index = 0; + + var indexAttribute = selectedIndex == null ? '' : (' data-index="' + selectedIndex + '"'); + var tabsHtml = '
' + getTabsFn().map(function (t) { + + var tabClass = 'emby-tab-button'; + + if (t.enabled === false) { + tabClass += ' hide'; + } + + var tabHtml; + + if (t.cssClass) { + tabClass += ' ' + t.cssClass; + } + + if (t.href) { + tabHtml = '
' + t.name + '
'; + } else { + tabHtml = ''; + } + + index++; + return tabHtml; + + }).join('') + '
'; + + tabsContainerElem.innerHTML = tabsHtml; + + document.body.classList.add('withSectionTabs'); + tabOwnerView = view; + + tabsElem = tabsContainerElem.querySelector('[is="emby-tabs"]'); + + configureSwipeTabs(view, tabsElem, getTabContainersFn); + + tabsElem.addEventListener('beforetabchange', function (e) { + + var tabContainers = getTabContainersFn(); + if (e.detail.previousIndex != null) { + + var previousPanel = tabContainers[e.detail.previousIndex]; + if (previousPanel) { + previousPanel.classList.remove('is-active'); + } + } + var newPanel = tabContainers[e.detail.selectedTabIndex]; - newPanel && newPanel.classList.add("is-active") - }), onBeforeTabChange && tabsElem.addEventListener("beforetabchange", onBeforeTabChange), onTabChange && tabsElem.addEventListener("tabchange", onTabChange), !1 !== setSelectedIndex && (tabsElem.selectedIndex ? tabsElem.selectedIndex(selectedIndex) : (tabsElem.readySelectedIndex = selectedIndex, tabsElem.addEventListener("ready", onViewTabsReady))), { + + //if (e.detail.previousIndex != null && e.detail.previousIndex != e.detail.selectedTabIndex) { + // if (newPanel.animate && (animateTabs || []).indexOf(e.detail.selectedTabIndex) != -1) { + // fadeInRight(newPanel); + // } + //} + + if (newPanel) { + newPanel.classList.add('is-active'); + } + }); + + if (onBeforeTabChange) { + tabsElem.addEventListener('beforetabchange', onBeforeTabChange); + } + if (onTabChange) { + tabsElem.addEventListener('tabchange', onTabChange); + } + + if (setSelectedIndex !== false) { + if (tabsElem.selectedIndex) { + tabsElem.selectedIndex(selectedIndex); + } else { + + tabsElem.readySelectedIndex = selectedIndex; + tabsElem.addEventListener('ready', onViewTabsReady); + } + } + + //if (enableSwipe !== false) { + // libraryBrowser.configureSwipeTabs(ownerpage, tabs); + //} + + return { tabsContainer: tabsContainerElem, tabs: tabsContainerElem.querySelector('[is="emby-tabs"]'), - replaced: !0 - } + replaced: true + }; } - return tabsElem || (tabsElem = tabsContainerElem.querySelector('[is="emby-tabs"]')), tabsElem.selectedIndex(selectedIndex), tabOwnerView = view, { + + if (!tabsElem) { + tabsElem = tabsContainerElem.querySelector('[is="emby-tabs"]'); + } + + tabsElem.selectedIndex(selectedIndex); + + tabOwnerView = view; + return { tabsContainer: tabsContainerElem, tabs: tabsElem, - replaced: !1 - } + replaced: false + }; } function selectedTabIndex(index) { + var tabsContainerElem = headerTabsContainer; - tabsElem || (tabsElem = tabsContainerElem.querySelector('[is="emby-tabs"]')), null != index ? tabsElem.selectedIndex(index) : tabsElem.triggerTabChange() + + if (!tabsElem) { + tabsElem = tabsContainerElem.querySelector('[is="emby-tabs"]'); + } + + if (index != null) { + tabsElem.selectedIndex(index); + } else { + tabsElem.triggerTabChange(); + } } function getTabsElement() { - return document.querySelector(".tabs-viewmenubar") + return document.querySelector('.tabs-viewmenubar'); } - var tabOwnerView, footerTabsContainer, headerTabsContainer, tabsElem, queryScope = document.querySelector(".skinHeader"); + return { setTabs: setTabs, getTabsElement: getTabsElement, selectedTabIndex: selectedTabIndex - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/mediainfo/fresh.png b/src/bower_components/emby-webcomponents/mediainfo/fresh.png index 701ef6a8c05e025f55cc600c1f36c81e90f09022..a0fbd46e2d959dd48e88858e22864103c2b4709b 100644 GIT binary patch literal 18192 zcmYJbWmKC@*9Mvd3GVJrad&rjcPSJr4#nMF3Pp>%L-FG7#ob+sLvc8H-tU}sek55d zcV=emwQW|SRF!3r5eN_f006R_tfV^Ra|ZHSgM)><-{!kT0RUtGIY}{1&+PL~A1C7B z4ASSb3|9ae6^U;YOJuO@a)C7+$o_1Hw>fC!Uz0|coponR&E;mC(q==3W?Mr^vx6m1 zR<&xC(kS5vy8MB~-XnY3y!YPZs$I-#egLz%lGJORzK`7N_g|dlL1yAqBPqr~r2SoiYT<3ruS)oHo2%MTl*W*Mk{W`(aVx z%%@PKFZbUzd3P<#J+zm0y~|ZG^?JBVRz?#Ce1|T=O(Xy(yq+%VaZ8GNYM|QQ0r|=D zx|x}4#DQzu_e(72LuoZwRC3@<1DahqM;)k`hkiT9p_s3I?&A(>BPJ(H()I_mWL(-N z!tTGcgya!*2suLvj+#9dG#L)M@yUT@K@A@xrjF%TXJ&Rr=BLK6kgw`z4d}0KQVO$a zX)X@PquguiF>F4y3ad%#Oa+YtaFOD}lEf)pf5>6}5Ub6`5@n9@os|Eq>AMI~4=(=WQH9 z2h9?UawQBjF74RQ1?9K5b*_D7Jpfj2?;FQW0(-+|jB=^}9*Sok{|iIPJ^_7oo&pA% zwI*fA7jZ+*B3lWtn3g>#2@nEnyY2Kwc#WUpCtpvqCqtP3ZoE;*sv~)L3i2YAs?s$b z^|a=bgNQ*+7E>uZ2R3?>9tM_FTtmd)-mNj{Nxn!LvLEkL(lL*geJU6Rc_XK5N5JJWtOoTh?>!(jtDV#kfQ@`J*_{IdL2A3 z@%;2u7&tU~=HtTrSl+Xi5*7sJqEgbJC6Uq0G*u_oG8hm8DUlG|uA6(=TRuj%HLiLv z*^~aL;Fd`HJDo?F_%rD!2F%PS_d^W}`S54Mhhh4c}9)cnjsk17JmkS?~Sjj>R z92c_Re;%$w+6u6^VhzNM1gL%~30yMna5-MTD*o&~VMU=O3!(_gemkkQYQMA52-Ak0h}|>2Z~#UZV>eO6SIn1#XbaOG@WfSkkD(!XaJKvplE(j_(QA zD&ga_DQfTPcs}aCGa&0*TcV4E?eE;ZOf#SWQ}uhU0;m*2T?l(R>;R{Z=nkp|IEX!l zX1@#$d@poVmV@et2t=HN7>(wL7elCd7bMFZv0)3v#zS+my3CJl`M7+yeR$Co`|$k$cbu7J7kmi98T&uAmO^ilguNV zvIJ_pBp~HP=Xp!hr?m-QhC~qHdm!dE|g&E`m9iu9D6hNE8ar zIZ}|~^qZye`3wv@@m>Gwp4L7LSz>N+`sH8xp%6gD^#^Azt$GF(Su`EQ4u$T=NjLBo zhGf*lMba>m)eShOUTsUh?kZ0WK8`voc5}^jLu_(pL~(uLAC+KS@%Rq3?EUx9DI1Ez z&`)sfMLz!YTjPw2YnvH0CnUFNM{Lize+c`>)Y?~Ef3;rs6D~gn#T~DnU;4QGg}9p8 z`s@21_#e@^U!ISnq|1Z!Ot0kbc(jQCEscZ-DB(1Pldbl`Au6@xyX(#&QBftp;NK7^ zy9(;}r1qQR7w5eJJa!%SWzN_*kL(@H3Phrkz8m(;# zHX?{*;rP0m3LpFqptU6Fd2Hl-1edRC`wOOw>pg{Z7oZz^uVQ(;#Sjm^sJ;g zGp!4mF>2e*M?(Hy&O-ez`%tWQdz;Ch-M$$UpIQa9I(LyeZWO7%uvf1Tv+ci{I4^7& z#_?7dxQwvMR4J0Tp;x*){;03qM+nrH>{!;u4m`ZM7WQ&EPj#L!`IGOrR&kRA!;SYj z9}4Y~@W~m!CosM%UcNyHP}@Pf=wQ5HKw*4?TtrY@&N*|OrJ+)ye~!6J=UqnP0~5*R zAfslBY=ECJ?)-Wa9>PS7)9ewED{#x>isy6A?b6}`fLdKl;}&gnu*D=Of#$_We9r(k zyXn|#_e$c(WFknKs~v2wpT9;u`1_7;LOdR|mt#vChDK})rEp*gZ#VL_`80zNrR(Jv z%vUpJ{_TR|Z3>Ybs6SX{*hZ`|W=cp*777Y_QO-%E%mC=2>E`LMj4>2-lC|Z zm>M8uv$4kX+HzzjOEf&^aP);q*U_!dIP}ApUOhXB6c4?%PwWZL>PM zsD$cpVcg=r5H;+-cj3=I%!c6jwnUAgr5ujJ$sT~q^2Pa02fuNjxafwtssO6;*nAF( zc=<8$dJi?)@cAFL#byQ%0ZzK~0aav20HV=vftk)q%yR?VCB<6*huM5cKMrwUuEo2wC>|bsNJHEN1PF6=gOKEWPqeho`X)| z$^|7W0fI?JCEL*sv;gAt-_;(nx(kQ=v#+eX?%dGrEN`k{&lcf|x@O3jsbE$fNGn;8 zROc3IZ4=qB&3)XqYWDEp+DSM4${EApI7OcNz&TTaLU{SSZ$w=?x;eJ9+alf18IJ&y zAjk;2jAR%XRm$j;Wi}~vzWlt&+}Jo=m<)mHR#x_?HdoijUN-@LUc#^kzhzPoo?gJg zx>Hps2CxoE6dGD|^|qdA!{D2?#i4yoXGhnGzF(mMFn#DBm<0#IcEIa`njxd{PZ)iloGT8qRCI@6bno6qU$Hy$Fn zgME{NvoPRqGg8q&50TlpsT`+>u5Y_IC4Z)%9h*S}KQTqRaBklH0D1(0UtxLd3)7nu zRo1LGmV-Bbugz@g8_m`Hq&FYe1sV(^w0dwd1aZMQs(|4uEV9fg#$hD`t-b=B3hX`` zeB>n9i*eo6B)U4iy%KE-dyTg!3SI3eEw>G~l2rS8OU09ZSfHGQQRpL}s7v8~n}K0y z*ImdEUux!Fwh8b1ivA1tNG+WXKx8T$Il|o+2%=Cv$)1-Co@x^(Y@-V|UzH}eHzT+I z+%+iuMGN8bQmN3SFQ7)m*(~!Dn-i5*MjDsXZR^$QI=`H+neIt+-sk3R_* zd-Sc-VR#56BR2g_WaI^|L}Xq?K$(@|nU;-5JoMZ)GlW6^o+(R+0o?R3=mqE^op8~) zeKiSN$XYdR(ghhBXSeZz=WdxDEQ365klIpKi_TV=d~dpN8s}x`!Ym+~yClpQesg3| ztp05zh_c<5`XybrnG6*8pTCEJi#nT1wCExaZ-`i4*%LbU$a}u=@gp!V?h`lS7&T%M z7ZH(IQ$c7^42EO%!v>{H*}wGgS8dFYFsOKe@v_{VZN_>J)@pKFaI$v3KQx&dz3g(g z%&R_hce1W_Z3`oAFUwCWj}u6$L#H2)yXU7O5PGjBIW$F;j8Q_e%g0ot*=p|h84*7Z zsR!R3MUwCMI@iC9;uoZFA#%`Iv5jBB9ie+?ggnO$D5f3%BVYhd1V{RSlUw0E#wYkGACL@b){@w6ZF z7*n)SiWZIk61e1Z^1&8(G})S4?evlX%V!KC@_{ol#HFO8|F1ro!5iY8)^@8eIrb(P zbx!(bsKO9+ois>p{jJLaJ?%HK$tRj&WX$ro2are(`6YVapjB8fUv0t zwnus3Oa>%R0u=%y(f5L(6UPB*Y`#u;h~@LdGl~GgiU(AGeh---8@-k(NfndJ$+(lk zkGJcZAdcVW9dJ5@$9s7=S!OT#h!1XSLl3b<69>EwQ?0FTzXC_;z)Z{$lR~UsWa?6& zk$ODg`+Tk#&CFtKWW|>sx9K)|!4N`g343cq6N8iyW$xS}`$Qb7eEV7*mwh>i(jiX3n z3i*Mj&aDL=JGXS#{C@vtiE`1Hd-xqco-__e97mWwhD&cXcJ_z+^=Mj2 zDT$Zg#q=}7QI6i}tLA@z2H6EFoe6-iBN2 zt+cM2K;jOzQMO6MW->Cm+}SA?iT7=ll?kzb^EZTY5vzi{IG#d8bMY4V!qUR#B!_E5g_|Y(I}rap`v3 zb8+7_E@5j5NV`5xcIWusYy@~T+c0`60V%|`Afdqj9U(el7E68QvR;KQ%8HZ{uSihMq z!lfIU1pAfawsP-Lt(ZM4I&f_< z@hjuOcE!PlhHbeEV#waei^^nz?_t;|b*YB}!hg_04v=y5C~g1mJnXF6gSCpKKY!@6 z(1g_+ubpOwC}9WHYTI;FNPPtV262rpos*{>XY`j3&v z?pT%zZT3;fkH(p#I_Y2U`s(ps)X|{VRr#0^Ayu9rEcIYW|YY@eV zAG!Z{^nA$KRsT@4yhqw5(-)Q`x7FS_*>nXte-DN*0awGkPy!l^#$2AiKYR}AN}eKL zv)u{FT`_j=X9ho2?|t{&8hK4#f2kO}c4?2?tA-&}g+xwB5RZTqko5k6_V^6jZ>5Jh zuO{6B4ODwY)W8`@l`S=Z4+9&S;?@{KHAjT_lo;5`vm>z&a}bN+vm z`NP(lSiX}}XN0en)rIg#Md?}pD9Rk+qjfsiew`kQs01XvBu(QH>YHQ9db_MYZ>?oz$qnB>^VC~bd2u&)+d30DGHrV*pzAQJb0v9!v3e%wcGEM zzqgF>zG5X3fC^dxV-r|c|3(d3eTQDwcbS*^j&7Ln=rO7bp+Z5!oUjN_gDf|Uyd+1z zJil&Dwa>Lfzym4Z%v{N5b3p-;cwPNAAvKs4lpMXrar{fgRKDinvC}2P^W$qmb5%^| z76ED7kxLD^sJY(ZBlQeGSIL=J9Q04@ZvOc`|Ta?)u$j_uychIeeKzx6M+c{CU?F zme5<9B}2-|Ar2XK(J97=Xyrf`Z>;oMc4nvwCRUMoyKjUF=S!y_o1(k6B3p;oN5$lW z@l?RB&E|cY$#dY^d2dm^DL0ldM;(h(R($?56$DcSaSAC*)=S7z* z+G@UzF9NbHtDf8aSp>G8y3DJQ(KQ*0pG$}f`FyXJC(!{h1xYwkm~Z|^?UyFU_I`hl zFTW00Y(o9{(;a}!!!l{65VT{$*tmNVru{cKOdGE;a+)=kjWz3WMYSm&85O$OpXs%; zGK39XoFIG!@M|IhBNtfH?`-SCu&TY(Rq?uhhWVJL(}x;_yxylO9413Vc#`{`aMH1D}9d`Jg#kGL7yzH|&ou$(G2eJm^bJuaSxyL1`zJ(H59>RXMhv8 zYq?fcqBp2o?dEcrHKZZ{)8XX|Ygc(ubr>MX6m|9roW7o-n-JaH`5e;eyS zoN-CnW0LYM7K$i6GPw36hw(J|Agmg;!{TxUnML`K>?$Ck;+_LUSGU)B-)EYVYy7^J zH7eVZ5Rz#9(nA{#=UsYbn#{G$FO!J5o%ONZT6;PF-olz9UwJS$Ry!Y&zxk~VCw{WJ zkCd^|{9>KRnBRNz@m;gprS#m6Ek$JqJa^t|`&6>z0QeL0Zt#6RM3)q1n($_!DHw$e z*8P=|E>n5K7vSZ<;fd6f^p0~~s?BF(9my|Aq}zjfVG_5-);&Q?osj|J?iNarnWcjg zS_mvMz(gi^b#3G9;+cyVy6vgl>I{W6*6qe}nLP+10eK-DzRaa~;odv+X|Nbo^5v@I-1Y;MXe0_qb(pk5WMe~6B0yuHNZoBt zCQNpnmrRK{8uE5&0g?I%wVqG?pBaXd_ndkUFsw9dj~ z87jI(HW|1|EPB##^sk!QxYyqgkc{6hij&t&v{Ei%9a7o`Ty*b_DvEHFu(U&BUpdIW z_J#9*6y65Jb-}DgJTlBH3Oxi#pc+8M2;<1x9C7!HXN9G0Zp42)>f++eHmEK{tv8&a z3ar8q7h{gV#uY8Zpv%IBjP8YDfPQ6mdR1*_Z;P#5-@xAcGO+;Xc%owR%g&1c)%zTsLbSyMA@c=F4>- zFJUVTc1nId_vuSl*QAW7atc>2oWmPOGb!ZgjqNVECga4HP1oLCt7J4hlil(4Kv-HV za`Lx-%WW?;ZVz8LI=p^0`q>3fSi@=-6T)z0n{IV_7zlMqxyNakIn1Z|owq}0J>Zus z(EjoaGU3_ObbsICVNclNH#P|wWKR@I&Fri^;X4=>YXXcg14-oI-LG^{{gg1%j+RQC z^98~xiRlatKJWdba76MtEw)SN7YHdd_${P#4BCu{wAgIR)w!tkw1lhncgHvN+BS;~ zQoyWc*mXT;FkAm6?q^?vocl3oZ@4+FeNVB7Eqzo(1XEX=9ajKKa1hrHcmV>*%+SHb$)Qg`H9GYj{h`&E2OoD$__C=GvP#m3eSg5 zDdFSLw`*o9nXS%7rsp4l0j`lW6##wE)5B&v9 z{mD9{#)b@8rbQfU69O2kUFXYY=+C`(+k5|^DLTrl7q^W;a0rbRhsk3owx`%Q71TUSt~;~+0{`@D5%k_Kgaqk( z{j1RC_B|-~sHjamV9&%tx!Tx zFWQ%Yd0u2qr9?Q%9{40(1=*o=b<*Tg0OTD zBS)Y^ZL_ogXT(KIVnL_MKp%%gXZG*Is9#*t&y*=4)s9xg!_VxRxN78;Trxi+iE ze;vdLMc|sgy|3kwzHj3%raV1nFyo=$G~N{w{O&FFL|Ccwh;BrD8Xj(R82mZqFh8yG zu-gB37XSwo2Mtip``LkrJ|LCo2B}gY>4M4QNo#jhfMMJ8T6>l8Y~?Q^XjVgJbv-nA zCQehNSazD@TLLUoEYbHzI>9M3^Wxss?3e}I!>g^s+s9r*6i3VPTE@-kIg)2Gt@ecq zZ-Z?JfpaYlkP3h2`Dw-UWmlWf7A9 zYwrG&rV=Q0-ZgTO4I}M8M0hX9dhb_Qx_m^YJNpFnUsL3uQB9AZXJ*a=#2+b-hnZfZ zmNNJQBs#WVjAF>H_i-UHy7wPZaeYkDs+3m)p60-8Sgibuf`GLY|1YCT?}&z|r+$rQc8< zV&Moj5NG&vnJE-cI9cC*ap@VpslFo9b$k9jlwXttuy(wUwe_l_%i9(-=)=L`V-{#L zq#tLGPUm$K)H7LrAFP;27-uwn$i(4ND!{fPj&FgGgvGa+`N!wO)eABgGq~pVgAn5B zW)Epjs<#Fx5j@n|^cEUbS2V@_5|u!kgc|Dgg9>J4)K$E*QKHlv;ARRbwlN6SG&gQ9 zhP@e|fU>7Lisu9Xd**JdACFar>b-_D1-$#;`Q`QOHRGqG62g#VOr#zdP^wcZ`5=b@A-#l9@hG|%os(xiskt(r9j zUk1^CnSzC)SV{+<(8S+W33a@7#qE8i2w{FI6N8hcj!h&0l2h2{;=>d}$g=zCBLbgN z3*X1mWfekf9_E6GKb|1m8_d z0#;Sg<0|dQKg!2bU{Td@NEun7M$Ge<`ZJ`4*rH3WMbTru7;k8*utUFd2D709vE-J@ zPUL}6KWOg~;ZG?9yNcXR%S<|v3s%R;B%U-2;&v5kdm<=kl+{Ti&W#i6 z@#y;z^h!3Ro|?#0p6ALxk!mXxH9A2FW1&R}wf+mQ(IlYWwZSX!RJ%4^6zBhBfk#ZJ z1~`H8-pU<>%J!%*n>5D8LHarfR0pT1`hwoZ zRFfH7VTz#BZAwz7^je$q7n_sR8DyLtF^c zzWqRrGTjjZnPL6tsP$kJLzDiepIQ4d9C+#9xGh&Df^ATd3J)-5?rn?Q*bZD*I5)i* z^4&C%DocuTgTLQojyx7gSU^1oQ4_3OlINFJe^VY7CMN)k@8khKO%o`_+TdYLik9hH z7jQ|@WqT7-&MP;82m<#LLL|LDRmZS4esUm{YxFO8r#!9Ke6gAB#s8LT#0suqWwR#T z_)`@%&=7v?7xfk%wu&~p1()d(r`&`gfz>oKtdfEgR&5sR=5#BF-Zb3{7kfOa^`!$9 zhLDqhz^Fzw!Px+6iS7tee$f=G9s)yN^%k^v5G2YkSfMe%v! zz)(73Rb&m(VmvfZTp{VusMgjqP8aTH*3hI5eSM+y_55dwB#N`hKo}}-#ckD-Z6s79 z%`M`wiTyp=Iwb1&e=|LlD8gj@Og%jIX`3;+j&7$`g0$6if8z3zog;&S;=?R>Gi215 z3~o*wYyyM49W>fYm>9LR=~xSzsIEAxC5J79>#C;l;$~bzd$3zm!GLOEOx@#dI^*(h zQRJ81r=KuuGcpdI20L8Tf$oT5Q6BMr9kNQA-Yjiptf$kt;pBP84*Wb8kpo3I1!VIA z$!;9Ts(raAuT0WIV#!l0yLqA*{sW36B@T>$yt!TJpE6G~ zD4&K&$PsXfG$qPK>%{F2``nasP0SB{^iSJ_KQLG0u=Vkk+^ZLWb9-~ooW)1Eb~)5N zl$KfJ)82e_v+n8M>+GonWmzB+leYs(F{w+N!E^?qhQNMd%mOuYecMVedx7foAJhZ`L zhxRN?6NEfb0U%myl3NXrcKp7EFoG)i*s$zT&@8#4+;k&eXB3f>9nTl4`b3`aAD}XXZVSKjj!I+cw;zEP827pRkELFEiKbN zKkXHq7>v7?=6Y-JwC7{AmEZ!@i#Lf`7!GS!AY=Lb!ybsN1Hy$(BbJUHoHeNSeVX-;|DArySXVeA4zNr1bxS3liEFec{x0z1` zwZPhXjZmobP}kfMZZy00h#N8$DP&8>f0dPBNIT`#%%ZcwY$|heIoJ35E6J5=$x45W zSu&rk)D&qhRrnM+W+$l^d%#nKiQOVSoxb07MiNQFyr~C>{_G9~I{h*&98C)Lt^_AB zI|H%K;1RX@2Re<}A|$3i0VAh%qZnUiHox54kSeKcM%FulwE@r)o|^v1W~s7zWZD4< zOrK!}=Qk#1$xcf`WO5!#0P7lR@q58}I8j+7h7IH^?U`;$fzMQ zs&uf=)DbRTad{?52NcGP&Cb=#4Ul^mT6!(M1Jo(f8a$I_WaOSIZ=5sc3W}yuG8{89 zCGFVA>U(p2o__Xn-0Bzl+v#3AtLj#i>OUgep9m(f%OU>ib#Wi=I6%pMD5SW8c?uIm zvz_=m-8*XcUZdEJ(~QH|wW{IO@r4VGUC;U~`l<|{ zdgSk`#_SY&xh9*`N;WB6g}^#8RglzBv5%E2%7qJSeMA#a?k>9dg-cVoyGPpu6Noid zZ5$ceHid?gc~{TO%K`Y@si5l?NI2FmxSkB)KlY^_<;M381n0V0FpMcS^DMCrVD%D=aTMhcR4 z32}vy4G$185q#7cBQGoiT#1!o3+$sKOkY%cvG9m$JuBuBi|peH?ujpz$cF=e~<$X##?rn-^92OEEA89J=BVC6%`qBN)q1z{M!4$-_t57Y; zrM_L_mFG2cCJN5Dn*-$Gi8nsa8MMywJDTe;UI7km5uxZv+@U;2{t}}~k^_=Zl=dR~ z3-wCW$5HzG+T!Tz9n|(fXzzTtJ$)H<&GmWnitj#BRu&m(N4=*|?R8pQ1Wx&3fD2et z5b!(hQ0nW9_CC2OzG%sU37#fV{xi9l^tKb8V3x}6?uM%G@jNnIrtw29t~WHKR#opqoY9>=W0ZFEXYz?WKSAI2&3>m4l5F0Ni?D z)PI~zqLER)BML_2D?3zgOhin!nho;fc^JoEG(LPrxWRFrjx5P3`kf|=gD4o-mTpF- zrLv(3@Ul1Fh=w`+=Tk1YBzh2{_^N@H8CaI4uQC^A#h6%Zw!6iWQ*0p@{zxEK2B8Km zyk{3YtBN7`j28tO@c@T|E5gd|mHpr(iT5}2jYWIF{a*9#N>t805^wW05Vkt5=b0k^ zyuE00(@=b5SE_gt8|FK0nE-ln$Ab{~f6mHH_F4O$6WDaoH1!&lO>f8kjUd~NTG%vf znF^Y(FqcHDKC~kP;n{?$+U5=gm9#Z3hI~UF=|pBCB|x<~?`d)^{;ELc46qop{iViJ z?q}_ZyvR4ZqL7wn5k*P&Q)H1Xz0RnfK+KlB0h9%A4;=%D;uvAEcfHoHOk}sg5O_WBW%dW9Q9aWq9dCISyI{!FRjU! zK-r&z0NM-4euDT?)4NcfWIF+02 zktKKlh; zq$mpGov0=rhyi>rXL9o(rbY==TsAJ5X9B2hi!gDi39<#s;BQT{rsXJ@UWwkePRub9 z`KOC;yI69`G8I32Ey;=4T4JtT9fgvWWdk@@7=q+X#}HG+gSR8T6MQFwpXv{XDRYjL zR>!Hqupe?al_tO#0}QLgJSI^rXh0l!`dx`E2_jd~k`~>0rmNdIVmTll*St)lQ(1~K zFb+EA4%gJIw|}dwcmF;Rl{J7XxX9f_Jhc}QHHeH?hcjUy;{%2tRo2j$CP;q#h*Fk@ z=C6dUZ>S)%>*g<9&RX>ab}@RUO3|KCt8r8e9k-JnlUfsj_R zrl@zr@1}6rS zsH>of;2X)P6E?cu&v|abBSqh4XsrAQj$9nqOI}9h3=yOwUImEOgHDgcm10`4r@!OW zO6>w73D-Rk+`k`b3izE4VbfH*Qhs{yqtKV%kO!mey(Y{nw{sVm2~R>5X{%cQtXp(; zLX}PK(-X`K?ZUyd(c9%maf*342^T(42Sx_tp22xyG4*Rv2BV9rHl~84?W2-vqGI)B zZLPX_oSPnIJ_s!8d!Wv@pfNJyQ4lhXp~?wu98h$S!swxr)Lno8AOdr#NWZBH*SN{*-x>;) z-YJoCgaHP$l%$%%WwmYYU2ym?(!fGd``;h6$o~UUO|t7cQj^X3$!=yi4bi*se1`(5 zJ1J_N=Hoj5DNcJTCU*=&;lz#s!MK8ZYd+zdN_D`fd9McE)ex^b<>>KysfMQ$OGb%r zDV!jHm??YnMw&IswLgt_lYf8ejI^j|{-?0-#Kts3`xkZS8Cg;5+UqEGw*LNk_Yv^9H$Ms+d=;v zK~ah_U>GGwc!;+$qc~le1-k7)jB4#uQ+PZA7wbqdCsGbjEC;h+%+xwD9J*`>#yrKe zYbFr?H4hIBE5P<|o@14IA;^@Q-a1+qU9W$>I#8w=;HP+P%AOh8@>TcPz&=`jz$KEWtFWFKqUOrNycp6 z{mNbD9;QSOKS?|x+)5bVQGc;2J6e|(-k#`9+6h9{$sBSV4cua zL?C!_%;pgXz@66Oq2~c(21?(>=bU~HoqQ(Oah17WRX>Q?(Lshpuq;uExfwCBIXjwD z9Dveh%!le?P)!s)CT>9?!nQ1J8Uw<1R)L?IbqaJyt176U9S}8oDp`jg)ja?v8Nma7 z7hwkBBaQ}uD%ATdgGSnVThT}!!A!VSO;Ereu)Io8QooUH?7XghB-+fiw*MzmPbY=b z0I(Vl#zi*{8{>GnU_7n&Gc)KIS;s1L8l@su2f)e(WEhe+b^9A~^(cG$AW|kJV(*yL zNT++;8fmjM;~PA{wit-k8G%PynMso`y33he319_|kUJ~xk@4YB*f@J%gkahxFlaP> z5^->v=2WB zi!lPt6vJi)UIWFkAKfNu?j(zs*Ux7Gj14FxP)9rnk@h~(=0nyrbX2l*2Njg-(*aTo zo$sy*7dYAeUkvb?S8C_;B@>c4W1f$pFL7hX&K(jf)_Gs$ebiLUcejW$j9k^@Bt{=D z{i^tz1+k}Sn&-{1eVh=dg9NdEFO}gazm1|eEs;&b+LC7%D9dBzicymFi!1avkj`CM zz<)%gp9z^qTMhmyP!lGuQV{p9@$LwlKzhS1Fz)^PsDW@Q)C6Iwru2yg(@emm$_kfO;Qphgip6)%eK5%822}_J519 zhD5=b-mvv^UdcjKljmPxo;v)~1+S-2RX`J#43ihxlYGaR<)I~Oc~?zMPFOKHejS6Bej_KXGju^P1IvjeeOu#haT(GC^>*P z;***c7|{<-K&1iVB@B5vV~IX}C~67j$7Xf3E&ghCG=KxjfKg#$vnkmDgK)eEWEC5E z8*9E5Df0hIMnl_A=9Qq9uzDo+$jLyGkU4G^Rk{Re#mC~wJ0vcb9(m6d0|3O0YK6x z>qlzY-?@0wo4JPCQheC4=zIrYpx{IOhtJ_ZEF^W?tu`w)rby^7@*ug1hezTy6I1z` zBDEId~x!S#J+4_q}y+_L-1aoF>XA4n20r%nz$)Q{7oU8WpXKI1`UB zm|9TvDEXLcJ{RVMZNoF4kT}*&`TYzBmLi*1u~YHAGC^jL^y(zCw>Hm=1U$TBUO8K&6O}ml_m*%p zKmz5oqy@GIo^0bw%1HM+i`UQcVY$_kkcgZ!Sm@nhBPIuU06I4=kc#BrT%Z*w+`Egt zJPU>XVuws!-j*T{Wi@hhu;8K&)=U%122oxjQ*Oz2R~4ruIP}D!^H|z@I7FnA=gFbK zy?|t9$aoN2)cLcoOMqO67asKdPgNdlPGMeIPrlQ`LBz&s(#b#4w&Y|ak={Tye zRkBf6Vp$L#BQ)MmkaVa7vIdR04awM#Oxdy{FQMSGPU#_dHMVrF809VT&cwW8=)nJ_ zD=K9M)bo=G46lIom)gT4X*F?k_tJK2N^c%yPBT@qbU`MroL~|Zj=az;lrX_=jKPOV z=Y7r_bO(SKmZxmG+6&&UJWJx5x`+72smz8Z!El05Y6eSrSl}b+lQ+huL2c?ELbaV@ z!BO6*-mM#*6@-|~IzA9WNnoViHoWNIsC@_P=kPwSg^fm;G$F-pwnv#qHR)0-+I$Ck zYhSX&EBP{mM3jheHkd0~bP4ky*$F}+#BI~;N6WD0633~-OlJUKFXy^v<`W4FW?m3n zCe1EvAxKE=C;hb7>!$UoU#5u1pi~VxvHhzCll$B+Ak}$sqVl0p-!jPM$~9d)?w;Xk%u0#Cz+eqwzmo z(px_w-dZz}HE5il1);R;xNBDgPh39btoSZ z*%tF`6DAu#CMtH`U^f7=@s0njVgDn~4<|A`BADOuY=htKnFZPZP1CH16Q z^;BAP09czl{3H7JJmhBaZJC8#wR~}kHak8|(KqpO-az$v+bY+2%2RZf5Ty=zZ~_3i z6jNCLt|uYl4XFk2Bf33ItSP%JOCfNOPvm{U_X1v%EY+5xN8$uvYcmpU3;@7(|M$ND zTz5hDfO9 znAq?RPw2!uXgE7Av^}-Z!4Q5J^P@SDr)Hj+S}O?78c@wZ?ebSrhj+RzdHY(~{O^Wr zBh1NZu{WDgnq##K7k^`!HzXVp$ZuG$??uFfMO$a5*dAx6_+4%KpI4K|ord=N;L3f& z-ui^j=3ns9@Ld}+*86jxqv)L|JVcion`v>dO6!}W+JaC4tS`a3M3x(Gh;NNZuI&Zshg&~4*h$_dCJga zv884Z0ZTkST0&{0_6eUS)U8VD7No&({7+q{s&NpNTE;|F_Q4w)RlY;eGL%Mwhq`s` zV**b?-AYq8;y;2K#z9o-qKN=tqNlGP-uP&7=8u{{;(&+xsX*dkKdl2xNvPYRQ8#}+ zhy#P)aNQ9@^HnT$0}-$c3=K6%BehTX{LZ6p0caXS-Q@ipFO9(?-1}5yJ*2K60)UC0 zzP+es&$=d+YQf{VRqc~dwy(bIPT-oACqR^ot%`jr9? zfP}g&9d(o12b}XK|6kx4Lo?PSivl8`j&H**fmEw~66)4`)Q#lf*s(ep5_DNK5CO{% zNY#SJbF11Xp>Fk{ZaRo6qi!Uh$DUgx00D~(B4Bv{DGqq3Un%eaNT^#AP`3cYIQGp& z1Q5^w5CP2%q-wQKLfx8|y17Alj{W%}0|;mkh=Aq;Qnldm+^Y6jp43g%NOuZ#qX7EP z4FC|(Ko9}IL{Hyg)Uru_9V8BTs9!1Y07$4?b5S>0u4lgG?NHSaX()(*rJYBrR{JE> zt@){&JOJ$b3*cC|r58^c4kEw@Qgz=yszRy-kLOmkPeR>lqi$Ras|R%x#}o&i{L2Od z2v{Nz0gYK}7Y97luM~IyB-E`5sT%>%;J1Ogtc9yomJCDyFwxW34G&0lU;SOJ_DQJQ z@}X{`EFPCUm^wiBC|NPYwjDJkhG#~=}aney#NbjoEJ_&VOcGL|nFv5X- z-(8~dk4c&eM1W844kE^UQnldm+^Y6Ts9SSWH&Lc%IB@8DOHAK%X*v)|5gSAvg@NA1 z0T1;n1s(tib!%?wCh6P0?*SEWtk?)?S`Y!gRyqo@2}-rvC!uc3lDfh5fU~dJv=5c0 z29cDBp1uL@fvK1J#{rM$R<+Mcp>6@dmL+u?720PQO)kpEAj-N1oE9C+sWCe}VwmJNuc-10ued=%c7DU8}Dp>E5Tx(&nAKBE!M-;}cKKqTcB zp?IaVPeR=i>bBUjY(XUDhBrxjkc0OE33Xd$)NPb|ChKFd8oNnl*@FlG#(H*k1318e zF9YaKs9V!hw5j1Q+2hnVn9UYSKD^%<-n&oFm%UJHwn7NQ@7(Bc;Ua?p_HwZtVj?^d28#A zUKbeRz~?!5e?r|Vqi!4+5r%@}f3ZTej!9NDh^YMC)_Vz{(4SDZNa{Ai1#td+1p|jl z0wRO_eCxg492nx@AK@HB9Oz!b)NP7$e%u9q$bsX}-9e`5dPxGJ81g^1^!9V`0Sf^j8D0-`#}f7^6-zXvGZ%Q+r$fnI5>STgFSgk!|ze3XN~vEELP-YDirzE&(I zfT@EdAX;Sk&cmiL zJXhR>n|xYP^7GsC0inp?nQ|Osa^hz-* ztctOVS|=U`hVO`l^Wy|h$l@MTrD*oiDbz<38~oSKHVltmZ3*YnGL}RNh30(LX5bST zs3A!4z{p8q+my|jK4b)AFfmBHqZ5*2K$(+4AhAY8zm2gJYtR9GZJ=SA=Kwj<0cF5r zg_%&fYzhyDx)AkJq0y>31;0IGE4OZvz z3e2N-ugZusFpN=HK5f{x>ii)2Ye|4&D=+s-NOK7;qIg&t@1XFAx}XRJDSg#dw*KN< zRMo=7LsYM;^=Qo^4eX%qux@ z8O>$$$7zINo}I+lyMqXiP(-U_D=orME+mXz%67D^j0z>W>8k!6zeB~x_i{CXc41LN z>%&2mbE_lxjwK+ZsPSrO$;$8k!gf`K9qkm0EB7t2^zC>)&SI>Ue=~fP0d=JJg}Efe zBsS)y%#1DxP0(;@#jSn%O>NCYO`Ek6!}$e++K%Qnf{oJW#j2%7LLPzY4d!ldsTdJO z-41&z4$GyoY*p?iwoieEzh_wgEjnA_1v=2%%+wX z)w^>QGQ31;!PM#+L8BLcooK4-Ma-*zN9koG@bxUScEO3(@{1prreNS$caq!^X`v)T z^}4P5yHCt&Vme;piniy;T1_siC^7BN-&`>W1E)D(brb%1leK)rIKapz`MMb?Ha(W< z$`Pab_?stctH``DiAt1g7vD_2BPP9iN}|r>KZ$*=c$5*ieL+53G;V(o(XLo|Xweg2 zK@S&^8_2Fl;d2IrANyF)F6Q@aJ(}xS*Tz4k&^fw8IgDT1yqHze)rbUEeZXTtzHSl0<529uRMgYrbg@@ku~_zN$QcpGnfW3nRX&g-59mf*j?s? zvOof?p$Ab)HpkdPPER4MnN08Ozm^7(crt2_uY-6d`W&p=aOC~ZQDV7Uo3o(0%cgzF1dBUMCBo{|@NLfO?Kg{?qtd$n1ifTE zgQlLfW0#K4r5o_*8&lxHzIjG=F2kJd{Sb`LrK4EhXda6i=;g$$N0i}z8e!)+8K zwbMvBh>pI!Bx>+Ys)3)vp#7OlY>K=vgVD+|MVmEEzcCVK6dJ2pCL{Cj;|9;YZkB>) zK?TYF9}aiKG=P@dIOOX;&x^&E>uBE|r~L_2q+^bl5_Sw-5W3*MvZlJTxTk9PZjI$& zd4pEvsxj#lR^PZH3G@q!r=LA{n((%_^@Z4|bc%&mwTbV>7@~zp?YM5!@|VR>Woebc zC5XyW6Y~gp5WA>$+8;rqJrO@~o|SQ&-Sr2VM)l>73@c@5SS!W3DVLO3@jgXGB^eBk z`NTreMYgTl&Rq0SMAguMkddVdGD4ZW!K`0jl$e-q!r4b5>%MVODrXzXVcEv)E*%Mj zHYMzWw1{RI=dG!Z>2#G`Zstjm;|a=$p{W$6FKrMKTX&@QBQVO;Jm7vh_)Jl6X)Ex z%NYN;)4M)56dRNJ_Y|zITg_ zbrsBS2deXn?&$i@47o48pPw_1+Q<8dv&!E~LA%;^(bB9x78(g3IeyE%j{o{_H)FP< z!^mpA4}MSOHdIhTl1Fn)x%EMlsbi{XtXJQtrh)OyTOA^bL=7e6!Pcl>Q-hrWp^Hx6 z@4eQ8s9622&)8S0ay5Ewyz`kipN8FIm3_ZpLpES@*zVYE2VqRcb*jiIU5j(cz{ADzI|Vd1Y(Bgw^9|5+a&@$8DiliT;t z-45nX6Z_7l`*@OAkI0dD=t}JiuEo^Exv%^sCOtle|PiYMdB2l|%{0oMzM>tFNyz4jMT)KM3cA02P5ai>OMVPBy`=by(7? z&fHT+u3d2$;43>|k_CBTK7Xc1IgL7CWj|XTuiyEt1lI?;`qOfcw(EAj+fEWOx?&CP zAjBRxa8TKW8S&kU(?CJJHYO$vwjP70H$cR7KCN||tK-{VI*ZO8=|%O)2D!Xz!oNPqK0w#yn8IwHV?A(YCHnp=@SbiYH+vpH} zx^6G{n5ioj;m4PmnloYGUC@J0GFd?&*Z6u376<{zQBMRqiZQDa0r^^@~ zie48}raSWF;~Wwv#I6Rank&-Vffe_TSt_}hIlvWd`LGZR^bpv)`6KfzV#l?+RR z=~+hH!GUt-PwXq@N4nBZRkKgN{Bs^dW|>j;vAzVc;W_EV9~JamN`r3qEN>5o(2F!& znC-<-R3)*JE;Kwehd`Hw>9E1*zFRRha);Q3RvFl7&o?2jx02I&pWlI{NV4r z(7<0QPzEiUVeLGi^oQdRY=HlCPa1Wvwljw%1zQg~EH>grl6mj9MeLmM8f^|l2mT4d=2)pLi53@p`$=0wwzjkwBy-`i^i zR75I*bOzj}C12U_2ajAOy$Nbm^;+$U8q|dANc_bha55kQrK0`5p7wkUe7Mw>Y?gd_ z)g-Ln$9WfmgzKbv6!vD38;9YsrH*ZHv4hSbxRv(woeNz7dwnw3Z*=?2f<*9IP#qS$ z=-bb|azXrSU$JC@!`7)#7s)WT+xi=`Z?E5zX3tf1*_e8L1h=ryL~r{@NX=djx65C# z>VNE-=C&kWd*cbKZp1%TOGg)C$cP_)TY3qS;Q#(mBQrizrOGm&GJ-GyB0~YlJOFM^ zLprJC`};fkE-{bgj9He@qI)MmYy-Ja+5Z(E4VV zN-^>VR0{u`#W#+RepP!>-{Tr18P+qjWXyE_JK&yk`N&K_D>A}N zeIf(Sl^ao>m@g2R`W{^^ZqUFS!fjGiZ%3S4F90W8%zA zM9u#){%ue7gRHh$aBoBj-GO#8twv$vWPW52V3QS?D9=vD%hQ>?klvO*4e)zgg^R)> z#0OodA|8UBZ(0kCl3U0^2Sn>Wvop45eNY>c-*$V#Q#U{_Lc)99-5nDUFg#iNTH*kI z+N-U?h7tn{^eH~kGc)RH(~Ttw!<7>GOUTCMbm;t-`LfWyirtSJ$7hs#U_B*|$GBSI zS#i(dBNQcR^Q9(hDm*Mu7#P*b+B&ypt7SN|EcQ%ez?xVTjT~7qqF~rg%|qx!d{8(f z6|ASpNKjOQ$`tEAsj;X22U#kj&>FEm*5=(|k_0$qvD|d_m|RTvVR1BN4dW6er9@US zkXb5xKkU~oAs4HgVyFnIyKXfBYw76X%PV-?Jg9S=e;Q%L%Bx|dQ9)-yBb@rh@_bja zr#Mf!F;rxOJ+j!jiv#@Gr&EtuwmWSVko@a$F!)c_6kN;L*m+6jKUqx5WER1&XY@Tq zSP2ch@M}71qhjAw&DtdO%V$<1E)D0mHh8xT4Xp;+-ZTXjx9k8g$X2y`QXV5mnHM zZ-2Q0lEutL1#JlpFb~pGjJ-e5~si4m< z)jQxr(cqfD`Y4w4#$~K(uH(R|mYklSch2shBC4%o9@rf7>Wl2heG4!ShR@;%4%8kQ z9_u7rPvJwHL604W9*aMe7CKE@J8ah$_{aY!4eBlFXT;SqG~yv7AZ0fDevuw5#vFRR zf9j#boQ^L(M=GIe+W7d|Bv|dB+yT{2dn5yZ_YUlg^DzwAKP@#K*sLW8SzGn#WCPpD z`6FVpgpE?OoiQ#3r{fG+*!b3Ovn&F>5Pc6Ys6JJf@hfK^xFT=+l_K!Z9=D3=H>&CN z&f(JcX~PJXl2g&{+IBnWxC}Y$R~owcAra*g4y1iw9#+!@t8PMYyMKEco~byBU*A94 zOv@tq5_8I@-dj>mj7fOBj!(#Wi8VBD++?cU;cqt(`PyVLqwMu^!}I%+A|erzyMI*O zfa=TmvcNC*I5)#qYf*qc^j@)n3*p>Dfg!2uGL5q6p0M`CY@FVnn`&C6Otic|f54~h zQdw9GwB^Ltl%)T*cvUbN)RezcEL-XPS#f~v=rAK$ubVX9h#|)ZyFN}cuP^S-G&#ue*C}ycV*lu~J)e!P zXj8)i?r8^`GJ<}Xke1?cV1f@jJ^xUye7V;=_o;IHRy+m$2rJ@A|FhL1$VSEK~JLq zOSe;8kEQjA$A{*gkbj$Vgw91YZ!QLDpz}N)U|KV;cxU+wZ^6+N^24gm4Vx4efzRVA+1Mf^;QE@^n) z^d{(Y>KR7pd+})f@y_$EIxq23%-n8LM*mypdz%O&Y!9xX=Z32 zjivVo*uFI#m1*H=IuqA2HvDT@ye=2daLJfvE{Jc0=>1%#nd+CCSdi{5c3606r{sSg>PC?G2RF1mD zCbJk%%hm7g>om+YzTrt3bJpQfZ+lsxU8iVU0@5Nwgw^AM9Bc+MJf2|lj0!gX;+Euf?pC=iQ z0*6DSs!G&`vv-ouhnYv{{&FZy+Qah7trRj6Ac7nB+WN+zq zxg$R4t`x(tNhsFOo@9&btJH|Pkd^l7_G0d*ncfE=LX@eBDqrQjJNtu9`RK;wNfWmH z#BJ|u&(BGwemxMTgO`(}&Ppxcml5X!reQx8`3m9!*J~b|09)Vl?Mw z_N4HSGfrjbiPMS#ed7BHUWfhDieCi0BKMq#JFx9VhJTArC>b6TW5JW^E9}ka&HxNN znFpK2BcE|uj*`_?w?1T)dlKC@XS5zXJ;d-I6e^ zSW36{$1`%P{B*DdE=*(-=lU}NTFMSYaAvrKl&rua253~z(ig2ed^LHN|9O;5INB-k zEFXD9I2iIQi*Y@VEQy!iT>y?2OTg1V&OeP@d@p=APT37iX6My^)C((9)k48e;8b%qGBt9#yvJbaQVV-o_ zR+v@akq-m0hzhHRqSUyeX*#ZN$pb_0D$mG8o5-o5?y}`XW%?Smb9*2hr_v3fT5fEqm7DSbi7^BlBnT+zuBO`4`*zk7e+|DrBbUmHah zVuu&wcO$z1{unh4n>Q4@Q(|RjzP8BJ;w0|=U7QE*n*X6F>(D3j=|8Uyh-=2cfDRi> zo=93n($-Q8w*C3ANOoh=SRPNUlER88pN?}B!)>0@3()&WKUgBV6pB8D6_7i{IFMqP6$It zZBsy+0QiU|kKBvl_f+}buNFkx{BH{emm5ZaBwe~DZSK=GD;40>WcgXmk;GBDqB874 zf{|EZdZF>Pk`KH80tp;ONPgadNPHU2aZ7LI@99~Su?@xkgqcSq?-#+D-Ew3TdlO=7 z*4TlyXh8YtL!^+tPCmo(%6XRBJNr zhpjLf8wIB~WJfWA7O;G)NGynUM~Oq(jgecBG_m^T??HM^coUq-Z6{1OY_^xax1Obg z4&iCB0?;gjzzV{*icJl+n{5Qj_8vmKyM)^L=fFgxmS#oSS(ngxaXrSvSP!QS z!)DDltoR3N&Q`ksEg;4TA}HPWH2#;v6uxCAWvv?}+d;AZupT{=>lB!no!Sqq57wvC zp@6v`+U&ON3u_#kIoF|nYs;2K*VJT1D$-`Uf0l`tFEZ;WbD!*2-ZNDZfxe08;soC{ zD81d72`bUhz!@tu=|^%1DKO|r<$WA7uRWB@dmP0%jL3LDap|iuY;>9cl_3<{4MWH} ztOG{U3!BPR?;{Cfmxi(a8n5vo6+&s7l)+8`vwoq_=ybRQ9YoB!8L}d^2QFX63LnwtP=BCS;dPPm;l8!7)jUqT26As1y6mBgm+U zWMEK;*$smTA#1%}iXIwf1;a`4=NG&_`YzR2(Q#1M=A12{ROxkfe{juUSNSac8OL)& zO?gTA-7arHUHcB8;Z@=xYATslBiLkVcvKG@efb(s{&irG5%R@(anK)7eoxY$+aJI7 zrR3-F>65!%NI+G|a<7;;!|?KdN+w4o8eH_}6!5m;K0 zPipkzeVvc=oce)+x=?BP4^ryVwVIp}ydk=F>E<2CsCTPRnH(;(X-QH(K2CS52~Af8 zZS~iO?re#V8IP@n1b#0Zse92l`wrgTk4Xj~2*Y-gRRsOLusWIpMn3#=k%E<~iRPH+xV<*wxE!^e!MJB>kb+)r`b5F_e~Hz>KWx8T>(3jX-GspyAlRf})N_ z#Q#yDlM@6F+x4dJ#AG?=VPR2XwDpF5Ayp!*Nt0nRa zbwB18W+t8c{+&hyh^G3y;~)9jyCuUwfQFg$QF=RPVpBb6;0qhI^Zfv|ENa-x$d6G& zA6MruH#I+KL}_p>>z(*Q-cQ>DX5$eWo7K{EZ!L}&wlx{=#p*m@{l_s(rr=06(@5y# zJN?h+&1AqF_n9oqlyXCn5LU8PW$EHQ-H%Rv^mp56ktv7dIgfH65+DglsNi%obDM6d8M6qpubv?TwCVVpd~4H z<23(+v!3SLlRUaBH5KWdbT4c?yN98Oo$uuG$IT$eK2Yj=0Yi?+tO1Z@L(3y(WT~_R z%r5=^W}zmE2_^4Yr!TB$VvX!%QAe=C(2sUbYnWOmccVI}>ZEI?8% zeOTA_mNOyW1B0wyj~Q!T3_3YH+*bejkeYUqb6RZ@{bb|Ly!?3jg{8z?wZ~DVz<6}* z=~Z`)&-9#^@(Zr~whlTGSlIj!A*d$3`p!|__l2PB1tR;()l2ypX+t|;!rPu^cId7| zQ*&6M*>Bv)he#@r>+jf1G4*YpZ5hr2_m8_6d5T-9ceB}mLj4~!e4N$UeOsaOixfFA zqL~ws>EK^`@eR@q2p~gL<5I+Vb8KUbCw8aRW!Wig=heH};-Lbh1UwTBGh}xL=UL;C zsKQsFluKsL94Dn1sHn|kr}a+U{dk$BPonqkU6!2SXgm{JuY1wYFR(BnE5j!N0y83L zxMLS!`Q|I+$bTQC>q&E|7N6$hd9sC##0$p`k;VfhziVEl0jkY0IOGKw>fFfw&E@RO z)oMfVA9VSx? zm2F3t6)v#l?FH>ut{=;Bjz?wIn|(EI#2gu+iaqS9=h^JPkcw+0wjtkV#*iFZqdh;} zkwe}NUFwAuo^v}vuzrAcb3x5LhpZm+WJUQpLgUPnen}>@pLly@PS-&V0I-=<7}oA` z#tgpLz+(HIM~M{H+DF%Y#(!on4+d3E`Y0m?Zh>MrV;iIqUjaF4xH&$u+n2AMY4;7q zwHPlHlFN{ltPgiWAjoLU_*-+=z?VAf_cE#N8>DGr!`}olq!J9A%RgB%hsaSs_m)yQ zR2hqeY^yZ2V?;g}|7JBYh|RqC^w|m4-e2VrM|pXz@NplI2+8<{4gImf=L%tnt06_g z-@rZLN_Zwmks%I%1k}aF|2-=)6an_H-pZDbAm-36_kK`AxoasAYvMxRMK&ablB_6O*2-0qfOpdvb!ysvfpbDAyG!sB6 zvPKMnIXvB{&l#vorWi)e-zj%<|827=iQXz&{5#*)yrMkWNp-*S2Y}RX6V|Kc!!n@s z7MrbdZ>D3j`<4Rv4N9pd`&MtCO`p*tjXz^|wf9pr-=z#2Fg^nm(V4D^bvdD7zxq2`eEk{WhWHfxqaxIP}V-@aF+&RFC610A)DX#^q3^Z0IkyW z&hr&3)`DkBiCaC}7>P-;u~DISyRBc<>&XIy&W>5c+cB9gl=9w4en(*=hRFakurK^b zwzG1G>?$cCf6S3kpGSLd2!6#>&~Z%T0)SZ;*-cMY2iDJ8kzLu++a}^4J*-fb8pw2G z|IL&b23yxKqBCvBF_<2qmax7*o(aV7?lveE1<-H;gv?8F+TexoV8+i@jV8Y@C#Tjbe)}I25yRi>3?Pw@bM;s2#+!`=9tkv1;-4sa7 zM3reYtr8$ns=s4($bcRqjlxOR@zD4fP-rLu$UA|)lzl(;nHVb;GX`6(+W8$Xu1qps zrNzS)Y94QrTkt?#lAH4f)TG5FtU^r`+)hiMn|A%(5Cn8q6-sCQN$~Xa|D^(KP? ziEEEoEpVfe)h$hD*YGP3WtB9W(tg4$bmW0BH`>*BvJ)7L@(l1*;#KINXwKI3me0T_~Sq`W}* zyy(Xd=k9VruTV(bkiyie~ts*wmAf z%s4IPsmQf*1g5GYpQg<<21l9Ier;@**qb%`O6Pk<`4ix{l+s7)`Z}Qm>_Rvhn_*pe zfuTre($w}T&S-8EEya>Iww#9@bxw*yZLjLwI}kii8VmOMhANOSyc#Qs1POzGlmkvTt(&u{qiB^YM7=XXml<17}S8 zQ#f0(!ti3`N1Ex7j3+w)d~%sx6`fNPiKJ8Z^!}zi)E(Z*c*PBXU&v(icJ+$6)2nR+ zkc1}hqh-BYQvHvT7P@bngC}qDF9rt;$OguXDDAZyYMuBZ%jAq%9~1Bi^SxSrXfWux zSu!91BzwGHTQydFPAcy@+h3MGpe}T!d+`pqO5qi?A zWNg^1(_~cN^NF!!pPAM&X02+#CM@tO=fG4&B1Rw?n$yUS@`{#1?tS*;_^yVvV1ltk zR1t@tkM!68npIAk+4ua=>o1hwj%bCB2xOG*a!4IEKJtwMgl9OE_DAVlM^|CiHD75^ zm}VvP^Cjg|M+FXTnKhg8M=ST(AURT%&hA2C?tp)yCimbvR}3N#i7ta5S0}{#Xg;ce zI9VPu{jR&i30C-yp>{!68OqO}1-N zBca#Ft`c0*-?Ol10PWrsqomvy@nIN9#{g$B^S`^k=lNm#v} z$eL#|_U;AfWfNn!`$A;Z?lgf_km@Xk{Or!r^viBk(o;XOvOiN?$JDY+vc)O!&t}{C zztMnMIR}lGAdSNJFd*~yg@H+8AU`l2IJTw^Uz@6cW0D)v(=79!=_=*v3SXM!M^CxU z?%^_bjInKU;7ta2|1!M?=)1)^3R@VKMN^%iT<&UTJprW23wBo+Xa%#Omv;e-gJtf( zGrcll&Gk+_&8aU_0g>%y*P9)W?vt^1o1rN@Qm~!_rF%wP${g?jH06Ni`VB5`*B+29 z6w3lvR|QB3Lmpxo%sq(=T$gbm26y1+2s#0%X3PVlJsEw1fopl z6F#AKi|2cA$(7R&ULczm8#F9!n^-ElI~v)g^yzPe;*_lpMP7Lfu~Q`gmnU`~@WMfk zO+KITx^9L1l89Js&Y9)$Tl-9ypxmeM*8t2brwO3Nyguw**!aAWN=LVsTIZZF0RLcN z75K}o=t{7UUZR;D|t?Eo-QrJHRq)T~&e$_YoK zIba9lqhkbkUJtk{Y^MoldNRiZ|CeUQ&ZK_KolJupK-5A&3Nd(Xo^;e_6|rr(xwfo0 ziT;R>uPxSl1&l_;TrzHWx8&ecPA<-1ma;$ogVBoyM_#T;Ec53 zXcQcqd)~c$>*;4E9_8KzmG6e~Z)avC6Hj2)WPa48XBCR>k+*6Xj)I|2#M;vNx1Un_ z@4>2nr#jg;-HGyPPn}k&qu?|;>ec6z{QEe zXjkh>JVMY_6AWXm)%fo0_e77-(?KDASyk_n&f8MQ`%mxL+;;HNh6qw(CYlGYr{Y3b ztCC^%@fPA3nu>Gk(O8uMF`s+KKd)e05XaWzjX;EH9qINTa%W~y0X_eZ#9l{ETBlr#0a7xLuOsJeX599cCbCX^f|_6|{HZ0k)+ z+XSf`k=|N|V(sW$?56xQ3Ey@NFBo&fr{u03Rjp5uy&L(QcOF+}Z8e@+fVcuCcXE)2 zV%m+0!g6c4>Eb00c>Ntp9_)jr_ELqn-K|f@lqka zTfoE>L=#G4aoCMg+byjqcJj$!|SL&fVXPEL2}}v<=rAWl=C|kStKtq^Ntkcemsq)3>&byH{%k|3UYL zAQtMvTZ~FtsHW~R*QSX5Qsp1?|Gj)nXEBIM@}k*gQ?U}9&Mitmz!%2{#_+E;QQS$?dqZ6wUeo1-zScifv zsK3sZ#Vkx)JN!qZL2zj?8543O+jKUC{teTWKK8fbZ$u`S>MbH*Ru?B>PKjLj#Vte{ zc9}*u{9%GiJpK@}z~OI$N2Wy(!jK`C8lE6I0%9r-1QORO60ZP^uo8eXYPZgo5qyKx zWF-6&0PMr0HCNkbjyVCIt5T}7dY)hTzpDq*qm9hLL*$N>?ISYbHb#wRNq^d3NJe$? z_07@6+kC$48v&jtN3+il*rxO`1mL94`dz*@aOcAePM67#=4ft26lTnEB07L*fli_s;j$KP%fh?0AT@ESY8rocnlgNv8iadYsU8 z+|+8WQY$cFjDN0fFmSeM*|>_Yv|2K=|LXLp)IjXp&M@-V`k%B0OR6W#IL{R6l40qq z)89)O+GqBRjcJm!6~+9GUB71bB_{{p*$7@PBkNJ-gm+tCooLiW^3$Km!=D1loA-IY zIHF!4WOk>UJnl~$cf%pU74gAjC{K={Kc(G*E2T*g)!pe#kMkKE-v>Pq(=@U}!nl(X z!b7K7=&VwuX7cX$VQ}}6+Z&Pm1(Fut^QgITN~XkdN62pPeBMGnY8~V$z%%5fMQzth zYpC12f(I_I{ep?o_hC*SHBsq}i12R@|L);gduLRK(}agBotKyJh|KTYrIL3NFM>>W zy$0hbR7x#z7{u}ycE)4(Yi>OxEER2z^sZ6%o?5*A)66GF>upE6&}jF3)$pID-|zzK zgxFN$ys4~3_7|`8cblhi;~Qh-tth9fh~!i4Yc)@uHGT?ydP-0_mGmumvBr0U{VinY zI{wV5>#Nh7hL$s*4I_v_d)Y&XQh^6m;7fnejns6*dydUF4P!sk6|+odYz6rL!t;&Q zX!93Ff(lH+AOZ{2NcIdV>`Q3bPPD$&whJv%NR~fKHJfqym#~C|PVM;rf(rh#US0*n zYMDG<_H9>xDCzsGWIs_Aj%&tv8QJa@h;4sWM|FfqVtoi3snSf1^R^-IPeMSb(s2L5d!mPp#lJuoy)Rb-J z1{Lo3Hj`k~LJ=q-OtG^x{Y378gyY=ncN_gWN06o2Ob^Z`DKVt?E6)oWAf;ay$X%CF zAiHp=`#858;>&&#qh{A7JG{Ul)rn+RAMVuC@O'; - if (item.TimerId || item.SeriesTimerId) status = item.Status || "Cancelled"; - else { - if ("Timer" !== item.Type) return ""; - status = item.Status + + if (item.Type === 'SeriesTimer') { + return ''; } - return item.SeriesTimerId ? "Cancelled" !== status ? '' : '' : '' + else if (item.TimerId || item.SeriesTimerId) { + + status = item.Status || 'Cancelled'; + } + else if (item.Type === 'Timer') { + + status = item.Status; + } + else { + return ''; + } + + if (item.SeriesTimerId) { + + if (status !== 'Cancelled') { + return ''; + } + + return ''; + } + + return ''; } function getProgramInfoHtml(item, options) { - var text, date, html = "", - miscInfo = []; - if (item.StartDate && !1 !== options.programTime) try { - text = "", date = datetime.parseISO8601Date(item.StartDate), !1 !== options.startDate && (text += datetime.toLocaleDateString(date, { - weekday: "short", - month: "short", - day: "numeric" - })), text += " " + datetime.getDisplayTime(date), item.EndDate && (date = datetime.parseISO8601Date(item.EndDate), text += " - " + datetime.getDisplayTime(date)), miscInfo.push(text) - } catch (e) { - console.log("Error parsing date: " + item.StartDate) + var html = ''; + + var miscInfo = []; + var text, date; + + if (item.StartDate && options.programTime !== false) { + + try { + + text = ''; + + date = datetime.parseISO8601Date(item.StartDate); + + if (options.startDate !== false) { + text += datetime.toLocaleDateString(date, { weekday: 'short', month: 'short', day: 'numeric' }); + } + + text += ' ' + datetime.getDisplayTime(date); + + if (item.EndDate) { + date = datetime.parseISO8601Date(item.EndDate); + text += ' - ' + datetime.getDisplayTime(date); + } + + miscInfo.push(text); + } + catch (e) { + console.log("Error parsing date: " + item.StartDate); + } } - if (item.ChannelNumber && miscInfo.push("CH " + item.ChannelNumber), item.ChannelName && (options.interactive && item.ChannelId ? miscInfo.push({ - html: '' + item.ChannelName + "" - }) : miscInfo.push(item.ChannelName)), !1 !== options.timerIndicator) { + + if (item.ChannelNumber) { + miscInfo.push('CH ' + item.ChannelNumber); + } + + if (item.ChannelName) { + + if (options.interactive && item.ChannelId) { + miscInfo.push({ + html: '' + item.ChannelName + '' + }); + } else { + miscInfo.push(item.ChannelName); + } + } + + if (options.timerIndicator !== false) { var timerHtml = getTimerIndicator(item); - timerHtml && miscInfo.push({ - html: timerHtml - }) + if (timerHtml) { + miscInfo.push({ + html: timerHtml + }); + } } - return html += miscInfo.map(function(m) { - return getMediaInfoItem(m) - }).join("") + + html += miscInfo.map(function (m) { + return getMediaInfoItem(m); + }).join(''); + + return html; } function getMediaInfoHtml(item, options) { - var html = "", - miscInfo = []; + var html = ''; + + var miscInfo = []; options = options || {}; - var text, date, minutes, count, showFolderRuntime = "MusicAlbum" === item.Type || "MusicArtist" === item.MediaType || "Playlist" === item.MediaType || "MusicGenre" === item.MediaType; - if (showFolderRuntime ? (count = item.SongCount || item.ChildCount, count && miscInfo.push(globalize.translate("sharedcomponents#TrackCount", count)), item.RunTimeTicks && miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks))) : "PhotoAlbum" !== item.Type && "BoxSet" !== item.Type || (count = item.ChildCount) && miscInfo.push(globalize.translate("sharedcomponents#ItemCount", count)), ("Episode" === item.Type || "Photo" === item.MediaType) && !1 !== options.originalAirDate && item.PremiereDate) try { - date = datetime.parseISO8601Date(item.PremiereDate), text = datetime.toLocaleDateString(date), miscInfo.push(text) - } catch (e) { - console.log("Error parsing date: " + item.PremiereDate) - } - if ("SeriesTimer" === item.Type && (item.RecordAnyTime ? miscInfo.push(globalize.translate("sharedcomponents#Anytime")) : miscInfo.push(datetime.getDisplayTime(item.StartDate)), item.RecordAnyChannel ? miscInfo.push(globalize.translate("sharedcomponents#AllChannels")) : miscInfo.push(item.ChannelName || globalize.translate("sharedcomponents#OneChannel"))), item.StartDate && "Program" !== item.Type && "SeriesTimer" !== item.Type) try { - date = datetime.parseISO8601Date(item.StartDate), text = datetime.toLocaleDateString(date), miscInfo.push(text), "Recording" !== item.Type && (text = datetime.getDisplayTime(date), miscInfo.push(text)) - } catch (e) { - console.log("Error parsing date: " + item.StartDate) - } - if (!1 !== options.year && item.ProductionYear && "Series" === item.Type) - if ("Continuing" === item.Status) miscInfo.push(globalize.translate("sharedcomponents#SeriesYearToPresent", item.ProductionYear)); - else if (item.ProductionYear) { - if (text = item.ProductionYear, item.EndDate) try { - var endYear = datetime.parseISO8601Date(item.EndDate).getFullYear(); - endYear !== item.ProductionYear && (text += "-" + datetime.parseISO8601Date(item.EndDate).getFullYear()) - } catch (e) { - console.log("Error parsing date: " + item.EndDate) + var text, date, minutes; + var count; + + var showFolderRuntime = item.Type === "MusicAlbum" || item.MediaType === 'MusicArtist' || item.MediaType === 'Playlist' || item.MediaType === 'MusicGenre'; + + if (showFolderRuntime) { + + count = item.SongCount || item.ChildCount; + + if (count) { + + miscInfo.push(globalize.translate('sharedcomponents#TrackCount', count)); + } + + if (item.RunTimeTicks) { + miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks)); } - miscInfo.push(text) } - if ("Program" === item.Type) - if (!1 !== options.programIndicator && (item.IsLive ? miscInfo.push({ - html: '
' + globalize.translate("sharedcomponents#Live") + "
" - }) : item.IsPremiere ? miscInfo.push({ - html: '
' + globalize.translate("sharedcomponents#Premiere") + "
" - }) : item.IsSeries && !item.IsRepeat ? miscInfo.push({ - html: '
' + globalize.translate("sharedcomponents#AttributeNew") + "
" - }) : item.IsSeries && item.IsRepeat && miscInfo.push({ - html: '
' + globalize.translate("sharedcomponents#Repeat") + "
" - })), (item.IsSeries || item.EpisodeTitle) && !1 !== options.episodeTitle)(text = itemHelper.getDisplayName(item, { - includeIndexNumber: options.episodeTitleIndexNumber - })) && miscInfo.push(text); - else if (item.IsMovie && item.ProductionYear && !1 !== options.originalAirDate) miscInfo.push(item.ProductionYear); - else if (item.PremiereDate && !1 !== options.originalAirDate) try { - date = datetime.parseISO8601Date(item.PremiereDate), text = globalize.translate("sharedcomponents#OriginalAirDateValue", datetime.toLocaleDateString(date)), miscInfo.push(text) - } catch (e) { - console.log("Error parsing date: " + item.PremiereDate) - } else item.ProductionYear && miscInfo.push(item.ProductionYear); - if (!1 !== options.year && "Series" !== item.Type && "Episode" !== item.Type && "Person" !== item.Type && "Photo" !== item.MediaType && "Program" !== item.Type && "Season" !== item.Type) - if (item.ProductionYear) miscInfo.push(item.ProductionYear); - else if (item.PremiereDate) try { - text = datetime.parseISO8601Date(item.PremiereDate).getFullYear(), miscInfo.push(text) - } catch (e) { - console.log("Error parsing date: " + item.PremiereDate) + + else if (item.Type === "PhotoAlbum" || item.Type === "BoxSet") { + + count = item.ChildCount; + + if (count) { + + miscInfo.push(globalize.translate('sharedcomponents#ItemCount', count)); + } } - if (item.RunTimeTicks && "Series" !== item.Type && "Program" !== item.Type && !showFolderRuntime && !1 !== options.runtime && ("Audio" === item.Type ? miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks)) : (minutes = item.RunTimeTicks / 6e8, minutes = minutes || 1, miscInfo.push(Math.round(minutes) + " mins"))), item.OfficialRating && "Season" !== item.Type && "Episode" !== item.Type && miscInfo.push({ + + if ((item.Type === "Episode" || item.MediaType === 'Photo') && options.originalAirDate !== false) { + + if (item.PremiereDate) { + + try { + date = datetime.parseISO8601Date(item.PremiereDate); + + text = datetime.toLocaleDateString(date); + miscInfo.push(text); + } + catch (e) { + console.log("Error parsing date: " + item.PremiereDate); + } + } + } + + 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); + + text = datetime.toLocaleDateString(date); + miscInfo.push(text); + + if (item.Type !== "Recording") { + text = datetime.getDisplayTime(date); + miscInfo.push(text); + } + } + catch (e) { + console.log("Error parsing date: " + item.StartDate); + } + } + + if (options.year !== false && item.ProductionYear && item.Type === "Series") { + + if (item.Status === "Continuing") { + miscInfo.push(globalize.translate('sharedcomponents#SeriesYearToPresent', item.ProductionYear)); + + } + else if (item.ProductionYear) { + + text = item.ProductionYear; + + if (item.EndDate) { + + try { + + var endYear = datetime.parseISO8601Date(item.EndDate).getFullYear(); + + if (endYear !== item.ProductionYear) { + text += "-" + datetime.parseISO8601Date(item.EndDate).getFullYear(); + } + + } + catch (e) { + console.log("Error parsing date: " + item.EndDate); + } + } + + miscInfo.push(text); + } + } + + if (item.Type === 'Program') { + + if (options.programIndicator !== false) { + if (item.IsLive) { + miscInfo.push({ + html: '
' + globalize.translate('sharedcomponents#Live') + '
' + }); + } + else if (item.IsPremiere) { + miscInfo.push({ + html: '
' + globalize.translate('sharedcomponents#Premiere') + '
' + }); + } + else if (item.IsSeries && !item.IsRepeat) { + miscInfo.push({ + html: '
' + globalize.translate('sharedcomponents#AttributeNew') + '
' + }); + } + else if (item.IsSeries && item.IsRepeat) { + miscInfo.push({ + html: '
' + globalize.translate('sharedcomponents#Repeat') + '
' + }); + } + } + + if ((item.IsSeries || item.EpisodeTitle) && options.episodeTitle !== false) { + + text = itemHelper.getDisplayName(item, { + includeIndexNumber: options.episodeTitleIndexNumber + }); + + if (text) { + miscInfo.push(text); + } + } + + else if (item.IsMovie && item.ProductionYear && options.originalAirDate !== false) { + miscInfo.push(item.ProductionYear); + } + + else if (item.PremiereDate && options.originalAirDate !== false) { + + try { + date = datetime.parseISO8601Date(item.PremiereDate); + text = globalize.translate('sharedcomponents#OriginalAirDateValue', datetime.toLocaleDateString(date)); + miscInfo.push(text); + } + catch (e) { + console.log("Error parsing date: " + item.PremiereDate); + } + } else if (item.ProductionYear) { + miscInfo.push(item.ProductionYear); + } + } + + if (options.year !== false) { + if (item.Type !== "Series" && item.Type !== "Episode" && item.Type !== "Person" && item.MediaType !== 'Photo' && item.Type !== 'Program' && item.Type !== 'Season') { + + if (item.ProductionYear) { + + miscInfo.push(item.ProductionYear); + } + else if (item.PremiereDate) { + + try { + text = datetime.parseISO8601Date(item.PremiereDate).getFullYear(); + miscInfo.push(text); + } + catch (e) { + console.log("Error parsing date: " + item.PremiereDate); + } + } + } + } + + if (item.RunTimeTicks && item.Type !== "Series" && item.Type !== 'Program' && !showFolderRuntime && options.runtime !== false) { + + if (item.Type === "Audio") { + + miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks)); + + } else { + minutes = item.RunTimeTicks / 600000000; + + minutes = minutes || 1; + + miscInfo.push(Math.round(minutes) + " mins"); + } + } + + if (item.OfficialRating && item.Type !== "Season" && item.Type !== "Episode") { + miscInfo.push({ text: item.OfficialRating, - cssClass: "mediaInfoOfficialRating" - }), item.Video3DFormat && miscInfo.push("3D"), "Photo" === item.MediaType && item.Width && item.Height && miscInfo.push(item.Width + "x" + item.Height), !1 !== options.container && "Audio" === item.Type && item.Container && miscInfo.push(item.Container), html += miscInfo.map(function(m) { - return getMediaInfoItem(m) - }).join(""), html += getStarIconsHtml(item), item.HasSubtitles && !1 !== options.subtitles && (html += '
CC
'), item.CriticRating && !1 !== options.criticRating && (item.CriticRating >= 60 ? html += '
' + item.CriticRating + "
" : html += '
' + item.CriticRating + "
"), !1 !== options.endsAt) { - var endsAt = getEndsAt(item); - endsAt && (html += getMediaInfoItem(endsAt, "endsAt")) + cssClass: 'mediaInfoOfficialRating' + }); } - return html += indicators.getMissingIndicator(item) + + if (item.Video3DFormat) { + miscInfo.push("3D"); + } + + if (item.MediaType === 'Photo' && item.Width && item.Height) { + miscInfo.push(item.Width + "x" + item.Height); + } + + if (options.container !== false && item.Type === 'Audio' && item.Container) { + miscInfo.push(item.Container); + } + + html += miscInfo.map(function (m) { + return getMediaInfoItem(m); + }).join(''); + + html += getStarIconsHtml(item); + + if (item.HasSubtitles && options.subtitles !== false) { + html += '
CC
'; + } + + if (item.CriticRating && options.criticRating !== false) { + + if (item.CriticRating >= 60) { + html += '
' + item.CriticRating + '
'; + } else { + html += '
' + item.CriticRating + '
'; + } + } + + if (options.endsAt !== false) { + + var endsAt = getEndsAt(item); + if (endsAt) { + html += getMediaInfoItem(endsAt, 'endsAt'); + } + } + + html += indicators.getMissingIndicator(item); + + return html; } function getEndsAt(item) { - if ("Video" === item.MediaType && item.RunTimeTicks && !item.StartDate) { - var endDate = (new Date).getTime() + item.RunTimeTicks / 1e4; - endDate = new Date(endDate); - var displayTime = datetime.getDisplayTime(endDate); - return globalize.translate("sharedcomponents#EndsAtValue", displayTime) + + if (item.MediaType === 'Video' && item.RunTimeTicks) { + + if (!item.StartDate) { + var endDate = new Date().getTime() + (item.RunTimeTicks / 10000); + endDate = new Date(endDate); + + var displayTime = datetime.getDisplayTime(endDate); + return globalize.translate('sharedcomponents#EndsAtValue', displayTime); + } } - return null + + return null; } function getEndsAtFromPosition(runtimeTicks, positionTicks, includeText) { - var endDate = (new Date).getTime() + (runtimeTicks - (positionTicks || 0)) / 1e4; + + var endDate = new Date().getTime() + ((runtimeTicks - (positionTicks || 0)) / 10000); endDate = new Date(endDate); + var displayTime = datetime.getDisplayTime(endDate); - return !1 === includeText ? displayTime : globalize.translate("sharedcomponents#EndsAtValue", displayTime) + + if (includeText === false) { + return displayTime; + } + return globalize.translate('sharedcomponents#EndsAtValue', displayTime); } function getMediaInfoItem(m, cssClass) { - cssClass = cssClass ? cssClass + " mediaInfoItem" : "mediaInfoItem"; + + cssClass = cssClass ? (cssClass + ' mediaInfoItem') : 'mediaInfoItem'; var mediaInfoText = m; - if ("string" != typeof m && "number" != typeof m) { - if (m.html) return m.html; - mediaInfoText = m.text, cssClass += " " + m.cssClass + + if (typeof (m) !== 'string' && typeof (m) !== 'number') { + + if (m.html) { + return m.html; + } + mediaInfoText = m.text; + cssClass += ' ' + m.cssClass; } - return '
' + mediaInfoText + "
" + return '
' + mediaInfoText + '
'; } function getStarIconsHtml(item) { - var html = "", - rating = item.CommunityRating; - return rating && (html += '
', html += '', html += rating, html += "
"), html + + var html = ''; + + var rating = item.CommunityRating; + + if (rating) { + html += '
'; + + html += ''; + html += rating; + html += '
'; + } + + return html; } function dynamicEndTime(elem, item) { - var interval = setInterval(function() { - if (!document.body.contains(elem)) return void clearInterval(interval); - elem.innerHTML = getEndsAt(item) - }, 6e4) + + var interval = setInterval(function () { + + if (!document.body.contains(elem)) { + + clearInterval(interval); + return; + } + + elem.innerHTML = getEndsAt(item); + + }, 60000); } function fillPrimaryMediaInfo(elem, item, options) { var html = getPrimaryMediaInfoHtml(item, options); - elem.innerHTML = html, afterFill(elem, item, options) + + elem.innerHTML = html; + afterFill(elem, item, options); } function fillSecondaryMediaInfo(elem, item, options) { var html = getSecondaryMediaInfoHtml(item, options); - elem.innerHTML = html, afterFill(elem, item, options) + + elem.innerHTML = html; + afterFill(elem, item, options); } function afterFill(elem, item, options) { - if (!1 !== options.endsAt) { - var endsAtElem = elem.querySelector(".endsAt"); - endsAtElem && dynamicEndTime(endsAtElem, item) + + if (options.endsAt !== false) { + var endsAtElem = elem.querySelector('.endsAt'); + if (endsAtElem) { + dynamicEndTime(endsAtElem, item); + } + } + + var lnkChannel = elem.querySelector('.lnkChannel'); + if (lnkChannel) { + lnkChannel.addEventListener('click', onChannelLinkClick); } - var lnkChannel = elem.querySelector(".lnkChannel"); - lnkChannel && lnkChannel.addEventListener("click", onChannelLinkClick) } function onChannelLinkClick(e) { - var channelId = this.getAttribute("data-id"), - serverId = this.getAttribute("data-serverid"); - return appRouter.showItem(channelId, serverId), e.preventDefault(), !1 + + var channelId = this.getAttribute('data-id'); + var serverId = this.getAttribute('data-serverid'); + + appRouter.showItem(channelId, serverId); + + e.preventDefault(); + return false; } function getPrimaryMediaInfoHtml(item, options) { - return options = options || {}, null == options.interactive && (options.interactive = !1), getMediaInfoHtml(item, options) + + options = options || {}; + if (options.interactive == null) { + options.interactive = false; + } + + return getMediaInfoHtml(item, options); } function getSecondaryMediaInfoHtml(item, options) { - return options = options || {}, null == options.interactive && (options.interactive = !1), "Program" === item.Type ? getProgramInfoHtml(item, options) : "" + + options = options || {}; + if (options.interactive == null) { + options.interactive = false; + } + if (item.Type === 'Program') { + return getProgramInfoHtml(item, options); + } + + return ''; } function getResolutionText(i) { - var width = i.Width, - height = i.Height; + + var width = i.Width; + var height = i.Height; + if (width && height) { - if (width >= 3800 || height >= 2e3) return "4K"; - if (width >= 2500 || height >= 1400) return i.IsInterlaced ? "1440i" : "1440P"; - if (width >= 1800 || height >= 1e3) return i.IsInterlaced ? "1080i" : "1080P"; - if (width >= 1200 || height >= 700) return i.IsInterlaced ? "720i" : "720P"; - if (width >= 700 || height >= 400) return i.IsInterlaced ? "480i" : "480P" + + if (width >= 3800 || height >= 2000) { + return '4K'; + } + if (width >= 2500 || height >= 1400) { + if (i.IsInterlaced) { + return '1440i'; + } + return '1440P'; + } + if (width >= 1800 || height >= 1000) { + if (i.IsInterlaced) { + return '1080i'; + } + return '1080P'; + } + if (width >= 1200 || height >= 700) { + if (i.IsInterlaced) { + return '720i'; + } + return '720P'; + } + if (width >= 700 || height >= 400) { + + if (i.IsInterlaced) { + return '480i'; + } + return '480P'; + } + } - return null + return null; } function getAudioStreamForDisplay(item) { - if (!item.MediaSources) return null; + + if (!item.MediaSources) { + return null; + } + var mediaSource = item.MediaSources[0]; - return mediaSource ? (mediaSource.MediaStreams || []).filter(function(i) { - return "Audio" === i.Type && (i.Index === mediaSource.DefaultAudioStreamIndex || null == mediaSource.DefaultAudioStreamIndex) - })[0] : null + 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 = [], - mediaSource = (item.MediaSources || [])[0] || {}, - videoStream = (mediaSource.MediaStreams || []).filter(function(i) { - return "Video" === i.Type - })[0] || {}, - audioStream = getAudioStreamForDisplay(item) || {}; - "Dvd" === item.VideoType && list.push({ - type: "mediainfo", - text: "Dvd" - }), "BluRay" === item.VideoType && list.push({ - type: "mediainfo", - text: "BluRay" - }); - var resolutionText = getResolutionText(videoStream); - resolutionText && list.push({ - type: "mediainfo", - text: resolutionText - }), videoStream.Codec && list.push({ - type: "mediainfo", - text: videoStream.Codec - }); - var channelText, channels = audioStream.Channels; - 8 === channels ? channelText = "7.1" : 7 === channels ? channelText = "6.1" : 6 === channels ? channelText = "5.1" : 2 === channels && (channelText = "2.0"), channelText && list.push({ - type: "mediainfo", - text: channelText - }); - var audioCodec = (audioStream.Codec || "").toLowerCase(); - if ("dca" !== audioCodec && "dts" !== audioCodec || !audioStream.Profile ? audioStream.Codec && list.push({ - type: "mediainfo", - text: audioStream.Codec - }) : list.push({ - type: "mediainfo", - text: audioStream.Profile - }), item.DateCreated && itemHelper.enableDateAddedDisplay(item)) { - var dateCreated = datetime.parseISO8601Date(item.DateCreated); + + var list = []; + + var mediaSource = (item.MediaSources || [])[0] || {}; + + var videoStream = (mediaSource.MediaStreams || []).filter(function (i) { + return i.Type === 'Video'; + })[0] || {}; + var audioStream = getAudioStreamForDisplay(item) || {}; + + if (item.VideoType === 'Dvd') { list.push({ - type: "added", - text: globalize.translate("sharedcomponents#AddedOnValue", datetime.toLocaleDateString(dateCreated) + " " + datetime.getDisplayTime(dateCreated)) - }) + type: 'mediainfo', + text: 'Dvd' + }); } - return list + + if (item.VideoType === 'BluRay') { + list.push({ + type: 'mediainfo', + text: 'BluRay' + }); + } + + //if (mediaSource.Container) { + // html += '
' + mediaSource.Container + '
'; + //} + + var resolutionText = getResolutionText(videoStream); + 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 + }); + } + + var audioCodec = (audioStream.Codec || '').toLowerCase(); + + if ((audioCodec === 'dca' || audioCodec === 'dts') && audioStream.Profile) { + list.push({ + type: 'mediainfo', + text: audioStream.Profile + }); + } else if (audioStream.Codec) { + list.push({ + type: 'mediainfo', + text: audioStream.Codec + }); + } + + if (item.DateCreated && itemHelper.enableDateAddedDisplay(item)) { + + var dateCreated = datetime.parseISO8601Date(item.DateCreated); + + list.push({ + type: 'added', + text: globalize.translate('sharedcomponents#AddedOnValue', datetime.toLocaleDateString(dateCreated) + ' ' + datetime.getDisplayTime(dateCreated)) + }); + } + + return list; } + return { getMediaInfoHtml: getPrimaryMediaInfoHtml, fill: fillPrimaryMediaInfo, @@ -254,5 +664,5 @@ define(["datetime", "globalize", "appRouter", "itemHelper", "indicators", "mater fillSecondaryMediaInfo: fillSecondaryMediaInfo, getMediaInfoStats: getMediaInfoStats, getResolutionText: getResolutionText - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/mediainfo/rotten.png b/src/bower_components/emby-webcomponents/mediainfo/rotten.png index 8f81822a9dd7eeeec10621c3bf72927a71f98932..8f35ea403acf38e2f9b877aa08d55a3db20d2253 100644 GIT binary patch literal 14428 zcmV-iIHSjjP)vi0tH;zj6o3=}vs3{=D0Zp!X$Fd41>t#9t@{Ib0$`R3D9@{Px0n69J0egY zV`iUv+tLdP+?>jK{kkEwzNmsT6g0a4n8gMP+95BwfwD{mV^v=rEbk6OM|%iv-z0HH z^g?9ewOTKY5txb-7#+*P*wqY-yMu(l>{Y=z8Z^HEn8jkBykRxoZ(ALMjkndo9a}=s z+#=b4FcsqVx$()|Jiw{b3LHL>a)ak(CUN3HGYo*KRakz)BnvIEx)AKRqaFtCia>X_ zL zox32zM}JAfl^YAPx>Pd35E4I$rwux~RTMHKDthkwb!2Y;Ef z9)2c86|)w0H&r4{DTyh z_6Yn?gr&?tc-e-~y#BiYngE#EfCar^N7ULMRn@Q`e5V;!_Jt}6gtkEfH-!)1T}5c# zGC_kj&Cb9PP@82b2VdfVWIw+6`eRMdw?YC%CbY_m`j=KPSE5y7seC(e*hUnIRtg3I zQ>EKY|JeD2@9FK8;9EPJ#p_1U_XSNe0H%`C1wldE1=g*K!Is-YB>|zqAlYH?0EGE_ zRA|-n5KCRVT7tW`iS9ZWP=CYjpm_$sRI1P(8db4xeyzSNK#&4}P-FmE1}4?aRYs|& z9=qeNI`w)@_SCaM^9+EglypI3AMV;*4-GM&fKW;Ug1AUF{<=N}@ZjA|;!hc5(+PqS z08@6`g_e7FMEnCnDGdlO+cvBV2T~>grs4&|^kL(=dZ@3LY6=JqR(1_wuQ62`u2~VY z{g$8vz?4fJ+r_+0aNC-?vH_9HCUOOWU5lX>8V3=DRrU3qTchGn>SrouPy%4eQl8d~ zeF-*g2x%_lG63Nu9r6M}tX12r**->H)-6GuSuGn3nrZEnr8cLZHm=@fQQG+2O3ndD zr;&dE%a|kae7@Y*;rv~_-BGx7HO=2{51MHJOu4*cRDJ2{2)j1oS^$FBze3nXRNx~b zFoCBm0H!QOZ&-c3;hZ7*UV)&hmO^|7!u^EW`8qp7j=w7?0Wf6&rnOlzQBVvJ1`Lvq zK;%&ciS~WnohD$~gJv24Q;yQ6zi4CbhwtkJTRykrBS zT_MYwJDE6*yC{;&_z8N{2sr*@`+!TOL6}b8mE-#q(JRNko7eW%h}Av|N+4nUFCA?W z+CU4I5Jd8%E)}Mpi4uzxq@G11rtd;vMuO%V0ONa!MncY5lnDqzTnO;ux+Vo_bwLS$ z@xRQ?%MNX~27$=4P23zL{|kUATbWJDCIh={K;%)w3WJ5Xj}I-PB8-LcYAra6l;)sb ztohiM5-|D$Af(Jd6bwslAPA8bD+0uH0%nB2NX#nG z)e)&_APO+@kJbn%C_$cgk|fJIW6;yp0Bx;x(A(1l4fXbWKNU|wd^!!&Ga0x(kyJZ` zv~?E*a2Jz2nAq?@08Dv{-moU86j-~e_JMF4AiZ`&cI*hMC{gxVLD{gT88)qNhwXQE zLvw4ia9dLa=lJJ0;k{3;!^~{PDtX>ezjp{~FlqaeO0%TiR zs^AI-di2Bt+q>Yw`86dzA{rH4s#u! z%2Z7yW1g=g9G0&3DEx5OT6p}CIH41P}#&FWO(3tlqfdm0aqNs6{D9|Kvvi8KKsgCm=f89a&(kWm%7UpAA~D#AlQ6995^ovmwy|N8ga zsUyKs25JGCs@gE@$D8JRlXC6C&12Xsb`T21Cn>3OWlX|tY9A0Dx{ZvkpuJj7b$q)-UeTR$k)H*10o-6S8rq- zRm=)J7af+b+}8znY-yqS5G08hZ~)N)TlM##!@;-XzKSgA@K7c~7HAx79}XNpuDP`i ze)u;V;is>jg0wkVJHOUvssT*dB@B}y*nppd;s?5hpnwHcMJe;OM_Zw@JybJ52vyvNqFt`^Nt;3 zHN1yq1%|mLp99OR!4=D+(AN`zWnE$F$rAPY=@|uP5(-?qk%jBy3q^s$ARWfKNzPvCEW7m^5mowTki(0~17hdgCrO8A0#bEtyVGRnI(77peW+VN}T)f1{ zz`}EaX;~_@Whtg-2z>Hc3NBwudlt*0YIgtjW?0o1sVWd|=fDPXV_b%h4ktwKSVyH) zv1Of6cyh2y@7+P~=_TD3r;V9Om1;y;Rdmb+iIBzR0hHHYAd#~a`Y)g}>UBR+C9_Cen zBPZuzDz4;o=@#k&_Een!a&SXmy0YNt9xr3T5&U+XaQEQdt(J_Sik20Wy{DZPT~~*X zxe#i!6Ph_x(Ou3oX`gNRqKH}9Q%;x zDk)(?KEpzL^OZeO`0<`*xMxS0jj}Uo!Ui`?kho@`l+2BmHMYJLVffCs+MvBfmlnI# z?|v!ArJ=|k!Lg0^|B`^=(M-`mKnXyY22m|Fogr3x?Uf2h7y7K$uWf*)#*p4fWd;g| z0za4a#%us3vqsP1qKj4Wu^NRih!h468=GP0l?8C{I0^&oO$OQx)-?T2YBt#rsy_OXRD@Q6|$m;Q7{cB=c zBj*V?c%Emy!3&Z{0L1*cS^6k0(nofbK1y!sBWuzJKa0geaMxzXam!~H4KS>Cr?3oc zZGgY|PK-5frhai-MKLFZ5J%L(rjlvtk@WqA6)BCLUV;biYk)3QRI{?rZ4{U_z&-r^ z@TC+CeK@PBXck+d96%6P{+8W$s>J8 znWT>%hNHf|V@s>;Hz`>%xF~>O+4AYqcw08q!(V+fDo70@HyHJnFt3=dY7qzNq8~?0 z=KspaAAX<->NK0CpI?g$GzUaz=2J4f`|%81yp$mu#TqbEB@DvS-r5v~ zUEhvbmXz?<&0c9t#`-Ys)}C)MRVHb6iqKrXo`w%Uouj?I-$0N&Cz^<7 zEA1Vl4XdX+3XzDW?kf727?|yts!Ja(fy~lp<%)WzF@eWx78qt=(;NTP*P5t-&l`KW z41Gn=mrTYub>Azns;AMj0mypsogmKAjA!7`;W?O_S9}E`-)QLUtX#3dN^!xdPMYwL zu#SrenLoLtCAA@aWV`ffX%0hkgLzCX5(^L1vV_r9v5gxg*0?HT=v#Yu{vE4V>AlXN zm(;3G(9Fzcsp~mDt@s8+zA`hH6|ZTi%+Fizg}XW(HG1ui}X=Smp&cs zb!GvhRL1ZR71>MC2KnR@F-;;=*w6=4Th+ETsb)-TQ=Mqof(K}DM16<)QXeTs_wFZ0 z6EvpH4|u zgb7DOpc?-DwJ2ep=F+9RTdInoZJc3Dp1o*;CZUw|=Fg{0=P#?V z&)mthL1F%BtC40+knUCbC=SwxK9{`GM=44ASS1XWH9MBoBrsI;;o_y$H1tjTve!L5 zg-I9-G%tv5=Sn~`pERBOSS5^o&ET(d-os|I5!35xNFT*T`qV}269eZb(}OhyjMz)v zc}J+KhQ3p%N?U8lsyY@5&HhS4lbEY$IwjpG?(PWZ-`nB-mMndU0h(9oqqs>Qhe+8* z`?Tij0@K!9M+wGQv05tG2B7GtbKSQ-`+G`3J3@4$IrZrR>hCZ=KGXUzN=PF1k8Acd1dqrqYd@&E1jDJ!= zxYn{3Q9WJVSLgp1R9gC|+a{(mRq1sKHTv5$V5FKc^hN1{AGEZDY;M#Npuvob2gEUx zV_zhFyZN2%rf#yF9-gO5Qpajd`lyC~I;|`UUXonb`ys|f1`4;Aj^Z}dnQL2<3EL7}Gs1-wB{~n>XG(~)o zFigtCMb!+;`H_@w4`5B79-*+SOiAi6g1a3DD-qDDmZGH(u}Po!w7t_(D&Ry375%$w z#L%}&9W272R(mn-Wfyy9L{!cEasb@6Cd#EuJLH(2P^5H0HIGJcZ(iR}dv1uF(g$)% zAIlgPEveZ|%>nZc2|^PVN`VDk$e5RH0HxPmTN+@|m0Z$Ceef7vZgDBYLNYT_Yrs(BcV z>8|K8&6y~<*DiM?F}i#2G)tP{LZuBRgHS6{MZw1M#n*|y7q zCUGv7`%(&((=2|`21AW1 z*w80=4ShqzNS+LRYw79?Lx-xnPfcgIL5;~eo~iZ5fDQb?yPK%%`tr2}bYmkp&oimR z8wJ*Wa2UI3ZHho&Pn5z}_A!?#70ZHCv?OOz6#=H;%$GbD?|*o@6?%I@CfA^7yNGk+ zxul?JVey|L3HynvnQ*)~&qgt;dtACGdFHENj^jc$;fzdG;dKfUd4SiA(L*J=j1KP5o2~M2WQ?TOlZ|#LHuay%?C)){v=4Qu1OHT3xz-!P{d%V7JM9DLq-+Wxt%B$|dMasyW#(#9gk`8wu#}>b@lX*O zkoexmvye&(ftWf6))9T;`-r})?V|oPiO7MaEUIEq_%H=CH|epcvT+GTq{_f@<$Bs? zx5Tf_T03s2d0<$GSuKKDDR1b$7d0$`OTY!Nm?TS9@~4F>y2C&MrNXde zlCo&GaOpC%XnQ#}lj_6ZEpJyRiBx;k@ zkk-^5N#7^$PbssPimG6i)GQcYlvO1HZ}3>0BB-$>(~6_S$ZNw)rfD!G3wLoUJ1cGI zmkk&JoZX;B_tGpVxNz(J_u$IPA>TsxO}2|A{H0ckIF?b{C|gx9O|qawz{y&PS=m(* zlzfkHYVmBAP5{F>Efzb)TK1^0?62m%k;>I8Tcr(_)hp{^&8jGLcZYo)(XXX37Yz;^ zuc*MoE5kWaf{cu$;mVDLq9jC4kKKYQq0%z-crBo}-Z^6&O-=b&Rqek}9q``B~1MO~a+j$)Xc{AP5RB6P`gZ z6is@hvZ`sR6at2|psn(Z3d_-2xJOc@8X8m6aH?%T{|ti~mv={@zrS8f@mhrKk}p=Q zVxZIz7=>O6CN(*6a!$2J@~0_62r~0oNULg879~aoB}OKnDpgEDOfGP+ zVDi1b-WaU(m@J#ZQpG_^3{x|WaV*lA!86ked~(<{joVgm93+*<(D<$FLfKVclq47p ze?WyLUTgPDs+KC_22Oo_82Wl*uy$?Kag`~qhJ{F(7oc?Wa!Cx7TD4K6LST{MG*0d>0ATDVHu~;KZp}lWj6SoX9o)kqd|sCLu;xjn|5izGQ(B z!08vjX%`&?nCTv8Oy-j;Qe<(80;z)Vz5Bi)T@aR==cc`SvJeDJn>$p^0mJ|pJ2*U> z{c|EXxNO5+w>R2mLE^7KP^2*2(#4C~I5(%j!FQ+i_mdarV0Lmo*CD7z?FY?kHF8Ve z-&zkRaRXj<2n^>VEn;{h<;_Zm=?Kd;;EeYJOv}8+R}sZv3Z!eIp?N&?OCd}$dU)f;vB$` zn*nayJa~T#w6|AZ7h5b6?EMdCVUjJXD&+OD!m=}vDoX$u0i1nY+8{I!Av7JeX~0M| z2IRXR7{FMvuLQ8tqRr3nKGQ#*yK67dKqae9U}$1=e9cudt5!pT zXYE)H9ZJIJ<&@iI9uo7as;UJ8n2Q}4Yu*4HkNMgYt=jBO7gHbr$6h`=oPzViNiQld z+BdlP)X`fNphXD`0|g<`Gt*$fluql{*LgO!19*)4GCG=tW1r8%e6k=eo#Nl-OJdcBAvRPw881C881S?jAi}p~FTL_L^8_u1}z!ztd zg@WUz&hg1($2eSz9VWjM`Sr8L%o}xoIWK-iPYn82)VWHPLZNX3X|aJ;>?AjF)77go z3}0M;(XmuHF7YU5PA?F+q^fJzZ)V}@wRF)b zm^?@$w2$b-G`1?l(gMb9o(eYZ6}?ed)*UISQCGF0)hHxVkw3;O9N;0X+W3S5V`CY( zaWezcGud(hbd&*9bKbdPS5Zb#p68&TcM8>`jT>Xo)wOtrcBESs4yp9-l)zp+oLrrNtTK+UJGzo_meCK zNi5BON;P{XCS-`KAkEHcS^DEDNVv2`i3OL4e5IPse%$^V0*pem`6~S z795g8b`B1QBy6-EYdtKLB2*$>yOxDH)qb6dXH<}~#oR`eG%vEi+u8$0gaxI_UE7)p z@=OJA6k&|}35VOhWrQQwd!oOWREQL~c~gVv`VG}K8eb?BoV_YI2WkcwD=d#a+PbLh zl%)zsq2E^xIQUvOl4XNru@w1t;h$uZz~##_jE*kA=;gF2HZVs)6>U!?Y@D3HFi+SK zwe|eYT66c1O`J- z&?5$49c;VhU|IZdh#(MKZ=O%$<%h#WNx^XNlX5tW8Le9Aw&2*-+l zaj%JqEPV9IvF z1~1vbvBF_i&$Q3%s+#a#fX28M$)f5>@WDru@X6sxNV_`+_OlE_zLbc|=X8DvN|(h1 zOU=Mh7GqrU6^@V&2Qf9s;^2@NY{kJLNmi*TIjdzn6jooxM1sd2?uK=1o8WhUyb9w} zjxOolssI4LpmCEhR2|DTzhp7O5x8-|)wZ$0;b3nVaDXFZ=7w&DL$cT=`Qb2bh9p{1 z!h8KUNSI(DW(b#BJ(3GOL1I=}`D_l{xc%U2$44BWUr!BGot zTrY6s_f+Zf$R>HfNh-L&A)uHO4sh7d)KTdB8sGo3*GJ&g*=e^YyQ7o{Xs3Y{8d!-F zv&s#JV-lA<8D8{{oKhD#Y?Jb2t;}^Xj%k@BL;Wx+&ln@otS{j(e{F1&EY}{gqniONwx3Lwi8-Iv}*hC?+K|V39Em@p%ANK2!++ZSVIwYpD;w!&m&TpZo_>dA?b1uq3k-wVRhLS@5XhO91iaZ3qRHD8vfe3+=gYLO%Y7B@g;lEZ_ka8S_3%G` zdJ=9<+9Cw{L7SRVls)65lF^h!KlpCPEe%I8_J;L$l+TT8s72o0xFD!L?rvPdy-_9= z%?S>R9btjP$=>@d~@Tv!Xa5u$pME{Avl~GKyynJ{_Y1G;s5;e8K)M5>A80L0Ze;a zYozLK+*@^wLvm1kte&dbSs8x)`gJ&eVHy_F_Uta*-HotjO*7nge+S&Qp|NB)Zaz57 zDxn3&65xssNFdzQfmpWU?XJ%|pjLMNj|3X&j8!i`%T9Byu0H#j8A z{`tl@yt;8OUP!^K`_DUq!pr#hJgtWh-+*N*JP$n71CQ_Qw%8}$$2dxZ!|eKXgP|Ze zB+0G<=V(AreQOeZm{}_j8)aM%Gz<-HE z7XH`EU#fo#nq);wYfB8i`@MB==l1pj;mGgCttB|z$`_|5;kDP#m2AsI@_qf{303zf zIXrl(BoiD&IKPuE00oDt=ZeP7<*EAk!|9@6!7`Ib!@hl|VZ-_kcy{+jXl;);j&VqZ zz>&vORV_H2%9gF2uGt~(sL?TvE4;a0x-_$nu0 zo-G*|Ea^0XhDNCd+_=TVVO6QdMzi{PG2{pHrg?$GiyOBvINaU1xyCqds&J}+3QpA;U@{#R6cX_G8{iS2d^KPf}7VB76PJ$kQgB$VJ(CsWYn-8auPO$jfADJ z9-5+ufrMBHh#qpn!$u^1JKsOd!%M`l5f%c1Yj?V+VtEUKqgGTqcCZdnhvv0koP*KP zIX%oq3rP{eesaYs@z5QyN>0{fj+Lx@goDTmC}LGXQ3P19Y~I`nZB4eYugAT9jT12M zXs*eOxzngH97ar4emKOKs+nm5zkGcLK0P|?IdR;q3eInSKM6Ok%dC+K4cj9e5^LO& zBOD?;LOd02bAZDhQx$S-W-0_Dg|sOqjc~9|pSnxb@A>(g!!S3S&D}eOY99{bB4p@# zr;1V6_uFO=50(PV5I6iW@mjUuFai$2HQ-S1nc3^}=dy6%H`6dRohkSkEMydT>ra!A zPJu2}%y5MBz!7l>I20v~GaTRmN5~d%7_zCXSPq{0PXmSiP9|-h;nE4edwMPl|M<^m zG-#aQker(T;(&v{$KeyInyGd323zc9`yG$18z>4GHu6c;vP+k;CJB=(8n2j4woq3!~U9j=vlSle0XTu42LNiHy0emMdLcb!J}~{ zAsTn!?rz%;I(B5Tl*L>3MjPvN^$Z8~e*M;y323GAHhI)o|gB=)XY>#>Z#?4EH zB767Q^C{T0sZQ$&bBw)|=Elu6#vyvF+}*gxkI%z9-aprxyJ7O?CWg7Y4UaU%n1+%5o zca#{oI#ap-d?!p3XE5I2nR2<`Q?UjD?1B)t1kJlFWd zx?HpD*j#T@I-U;?O_^0bU0R6M%RG*-Nrkh`<6t<2bTyanYrLkPv-kaL%su0|3zOSR zX|o^y{Pa;KY4!5kx5r>)c*b8(RoNtm`j;4zL(z{jKGTnpiEvH=u{vARA1E3ark2s3 z>*T2e`G^%7dF%R#2IOX=+a5^g1 zxQF|&M;P>j;n6uW7}&_e7BJl401*zUXgHiaRol0l)w22d%&x72tNTl7&n#1<$u)i8 ztznp*$@l|@gQrRaqr7lvpUdj;GJUQ6mDTp#(rosWWm58BDG~;F&x6MQnKSI>?4Wh8BqV?a^J6MW@(Nz^(mhIrs91}8<+2#myID~oQqWvL>aJY|gcy;4m zxv~Ji{Pk78VF4Bzp?l4yrm`@fp0~h(*yMska)raMF^(s{xz_3OOO`TBH8Xh)fBo+l zAu*jU*^P@}5R0b@_mh>v;LyBX8XSrYdgG@sFd$^%y=j}QohQp)7rV4;$b+h)t7d=x z^E`8-=1;2N4u>EuoZ!ge#!V#^_|@;P(J>QC87T!8%X!$i41ug7Ti~#(Q6kII>v-4sLJgs+jByhhl<*OB2O_CM(nH z(zYQq3KYAxYsf>-^DMlPk`(@&G0GLA&T_KYLpoEb+#IWvx=<`wvtUyMOwF6$Kg zw!^2zL*L;qaA6-=y~EXn!>v5=#F}zRnIWrcN>#HjraT+t#K9O>Ts&1yaEL0EA{#1| z!T?d6Bu5@N@VKnZB^6=c>39nUN(M&gd1!3Bkh8dhLB9;+J{mnVPi z=c7)kK#wxX5{EJrYdR&}cU}}6l5YcmJMLQsYgXCP2o0)IW|t2?d#~s*q^{;ajzVH) z!IP)T4Gt$yl`9;wS2z?49I^?HEVE;{CW605az@b#Zk@2UVy3Oh1mwb>iaj>Ky zLe=c;cg9L`;}!x3w==S$E#d(V3WNX$HTwCvvYNEv+Y_^9xB0@nx3xAy1>Q(K+I3_s z39tRXD{x^rr8n|$PPIym#?3v(!QHrHWApG&|2AAnSWIeNJTBK%z@g}^+J1MJP0FZ^ zuK%_jD}LewH2c9a*ZuIRNjQ6Us%ST^=&8yFhv2SXBQMmC$iXRp6|b_x8H}WuqC?t-P@OFyj?MFTv4sE!Xe9sCk)}x zr39@`aBwh)Nor&e6dewxjv*lQIGKKyq1$C!LJYiqUnPtvY1Fz?^xNa2Hoy4IW%#Fm z8HGr?W8h(G8~rYmwg9culn&aM;_|1oz+D2O0H# zFU-oK9`1(&z&1969pt~iJ!*KXL^$%eab*h}Spg1ijB_~j1~0qA!5s$fa40$)*$jt8 zrk{;nu`m0#kn*OINyWO?u;A2A&=R8AT$-zT8emmlBlNFnf{uS>RAc48MoPRF`l7%l`)TJY*u1GjxJE6Qmau4B`msthjRWBUk%X9j69M*~7{7_f zQfeIo5jqKC>M&@80X?ro?%y<()q zUWlq_EaN{W6WGnS;W`~y4;`5(%>R=D)fK|OIVBqioI|oJ?@2mnWLxx*f z@(xFpqH(c)d)I2HueVLR-L2X(?S4F4utamCs{DtcG20l2=*E?uYz~{jZm3{frOLA7 z(J(jc5<=A~{EkdUQ>(bWLifuMT?NxW$G;hEdnRkxH`i5Il9nWh^YI0n!>23~#>JDi zpAUX9m8~CgPXQfa^=LU=#KqV#HVNa9RH0mw!)+di-eVfGj-atA1lv{B@#90bPI4D` zocHfx9Bxn?r@&tNgG1NgfqR#mdUt;9ib5>+fEel(@9lxBQHC@UkJHsGK}v{{!*nj9 zbtoqFjXft(0-YT(PhF4~6quh*nFg&Z28@f!HUa=cuz1Qb*3eYDY96+2Rr10?i1X`$ z;jj*-nc!gRiDD!eq@Qc81-|~&Dkor`_5&C}HG9M4ga2X@)~;@buFiVldR-bc5C)CJ zev|QA6k<`)6yshg#C#tWVunxeQykz>M99?t#wSt`Pnd1J#0`BFW=~6$haf0U5>Iy` z7aOXcHyYO|R9(q2#*xR3yR0V)Jw2_~-!kZ9=XbyfzCXQp8IsA2F~;HI#-*y0;Hk>6 zu@d}TW~v+C$EIE})oLNbRWPQyWrS^6zMZgrWqli}ajBFH=SLGZ=`uG(?U|!q9VC%} z4|iZ@W-=y&)Xh^Rsv;(7;viv6-X0KpUh%zgGJa0QBBemM1m1&2W46cHuG%pJYGd%r zySSG@sC&)kk}`bs=?!@JzFys1#^baU6crZ9!JPt%Xrx<=f0H9X@O~*Es$PavaX!}k z8LDE|VT$RiNeVd#bD;tWQ=E~j-B4A0S2R>zE-qA^k8!N+ceL>be7rYk-#ugNVJ^?X znR9VXDrAV=7`MC@4fBj3K}0FSB?Ffn3r^cD$BO3=_a7OXwW(rh_5JMRJhxd7c)bUK zgmEr3`{&s8dD^JKA~_TXW86t{h!dR`}5bLbW$9pin0IHbQ*3>*+=y!4E5|4RRYHY zV0-`uUwnBs4jb0D<@HqMheJ@ih!Zs8*hPLg+{QR6B!%~@&|tR6-TX7`?LYYRIy^A2 z3|d>F4sa0t8Wkdprzm#MmkAD6c!+5q-ASMr@S!JfX4W1vHhFOtvI{boE-x4I+XGc)U!|>`|c^5LG@j_75Go3HNO4qS8i$ zLvP5U#1Uaoh|QI3z>o(H%W>#TxIUh;jkjp9%yBm|b(a?+T>@a-i*Co9yO@AM9f-o= z5XS{{3FH9|({UchI7UaND}A3ZrtqK$4cb*W>1_S#7FfQl-sDvj!&kh*VI1SE(uoiv zobxFeCZ`u1^9{^Trn%jMWxoo`fkJ<90F1kyj^46=!ZVL0pHlUDkmJ) zfJ3gZ8G~?UX(YnoJ>ZbLWfiK*iEiAhkpPz=#wkY&=H$Yuo z$P9XB{OBHjtqT-LH1$ZqA!qAgW56STqE65iM0P&u=G!V;z&qu*e24O?LK1 z3Z}2m@qtOMhLr?MAYt;C{h+Pf1)qNzhwa-d0Q-xC0n|G}G< z!}!Km`k-$`lTV@Q=27rML)9^{;ahJELwst^?eej)?630uLuq4Ll-AFZn$Ez?O&cg! za6s}!Kcq?kObJpZs_NX|dSVqcH${X{bJfrHW{se*z7kZiC@;eK zSKH=hvT*z_<8b|I-td>2QN@aYXh2Ze+F2d3I5DdFy8>VegJw5a!rHNPs8XhHc>}EI zY4kl*J*lcABc~H^?(_{Wmxzt)86PK%1tkEcJkapc)gFbm=BPHJ-554cUncoO)iE9l zqimC^zJ66zzb3CG#KE_GYRWTCw&1e4zzH(Nk$- zUOM*z#jnhXAszWtFq{PSLhxh)U}_nfesIb9S!{6`e9Kk#Lm6GDK?#5| z$~%6Bc?2Z@rX~toZek!34G+{eN4FCN+7($DNG8(xY@QLJUSyCQ4Gj4Jn4kn@QI;St zSx|x!027p;1i%C(C;>1*2}%G=P=XQw6O^C?B>*NUK?#5fN>Bn|f)bPfn4knD0469w i34jSoP=fOR1sDJ?yXBPXqg3bs0000(>&eI`il6 zMcKLT{)=hKsq?!7j6_!FC~xCB74lM3CJp+&oPI2i4L6>ANADkvJ^50fsC-UgbcvLn zmmrU(ws2j#*CG1T1EbRgp(fed1s-vLQ$5ks&`?YhXkP^J{=sJQ$T3`~DR{5&-g7W{ z`$Wp!X{MPPjO%2C8bfpZGvig)tY+m^NG-^rV8J(izqu0I%@yR-T0(&GjF z_Ft8mDddZEXEI{8a-Av@T?V;!Z4P`T&FSV@sOiuxk_309rD198%>5%BmBzhW>0d3# z2d`Y$N7a_c$=WL@BUWbYfd?_U>mnt%u0o;2Eu5|YWa#!pK>XpO)uq$Qwa*I1815?v^IBxb-1E;wx5cH2Zxre;*`H4c@!;T$Pn6nt zE2Fq2?LtXP&Jcf`HwSq;dx)D${G*`I#Orv2EUQJF>y@;}02p&`w*{i*6!53yD-7S$ zA)~o8Vt>0*|Mzo&@K&eZubJX=l5PzPw{j!0ArDNB#v<)CqK2&M(axzPeRwgZ!uK-dJGTU(6qJ2_o(<<^h`$H z_M9bWtkjy#mRQ)OO}3j@!wPMlH(D6VL3-iZse{Ve_qW&V@(_t^VrCss{ufSc??*am zR$|@$F5{pSuwIeZC7_=6rh#~}Bz%Kk!YiBiz4E6(&v=t|(dJ#3q8Vxa5ZG>ES7&#b zLQCeKckMyFlidX1oPst@hVWNJ#sn+}bx9hO_xoiQ_U4@g&-RvS6!CkllQ_c#f|%nT zrHBB})DYYylB?PfanX!U;=~#kW)93uscrndAlwUFL?&$%IvdGW5xXn+DA&C$v)%t2 zWnZffwEb(|O=$#Wj|i-tSRu0nAN|PCegAVDvmPNoE+WxZX?mtl#US&2HE|M{1RT18 zS1uT>+J}1j;;To&o-@?$uM+G_ULT!Hm+ux4(#qo_b*&&`M0 zE+oiTTemd^hKG}wNWZk`&h}|@<8H`v{EXPh6M(f%1C1thldUwZX*t)Ai)&eMremrt zmu_`vhl*~JuRQN0?jG!t%Z*H@FG_GQGw4{gO>kXy%b=oD5%EJ;6w$2a#S`lWDmeFy zOW98DsNBakdXvS1T3YIVv%?2FTs<{teC=%+w!c{RWgxWUG{435sek% z9=B2Z=Xb|#QYH@zb*SHux>BZ(iPz^ZqD^UKOBJ@X57>W2_C0P3Koo0u7g=P13o_Zw zV4+%n?&#NBsSAR%?1<31a5si1NH+SGk*N=w8W7E+nzXat}s9ql79@8@ea;Yx(u?o6H7RH4Ul%$MZn`cKbF{@8iBvV=OY z!33tqKg6v0LT%rFk_ERCjN)y^^<_~&FV?2GJb=9yv(|Gr0idtqbn1Gh@#XLHk^bA8 z&v<;Dczx-Uhy%04=+~Ya1U`y0-Eb?~>X+Jn{E*0yuIS_;#jVbuVdGpY!v==87&i7y zvOTQaAF}>U5EyUPDxEv`ArKI!l=&W?QEplJZ%LndN*F?R9=5md};^QF=i{ud5J?~4YK$8vB`|%XqyYKCZw22`_~o|+yCm%kuUSa8|!dk z8+m2A=a-8GaLNwzcWSMb5524oJ|jMu@{J4uO;VqDl303Cd;-m=Gh3hYCHJ6;bbjbk zsvn-?==3;FQcH8zvPk~iNm!hSNn6FeKg;UXyxc;M>-5h$M%obAB z^}Cp}Jl1}9xARKyYj|Ejeakm#TwmS+2FwZ)`ym%IufVwF5 zOBk;&P=yxlW9X?^q!_|6QG!p1A}i>l&1#t5bZuWF&GExl@h`~^){xm#f9tkun$!q9 z_k_`ziw4+BGy|%F_KJs?+`B|$k85xTeI3+ZzEyZlU#s!OaO^AuQ`kZJh2iJn{ofwn<*bkchw zk#FcBM2QkfQO~WCSf0jUC|e*ni_&s>8HnjyM(=6a6P%)xHahy&;4k|2Y(E4benm5t zau^3`p;vkP65JkL2@Ln$vS?`CSE}R4Bxo>dMV2+T7<*h~#O;0<2goZ}{ObDD!dO5! zFWMh2oWlVAwkiKHQbIR!65iE(c2;$f*kU`p*Mtjp^gS?c7=1fGqAk=Z>(3JiOL@kEqj=ior|ZK zE-v9O$cCW5&pyYCI=YQ^2l(CLJb~)0P%ne&dEjppsSB1h^yg6-V=cH*Z_UT6v9~Hr zjt$V4c0+q%?6#a~f_vP1AT#*X2_v1^mW!`icQTG_q6EMZF5%w%GE(tu67X1YbkwtG zeeD3F6~CU1L4|6o_!UiAlOV#zJWbI(+pS%1(Ncz0a$dP`$ z%YSR2_HS&<64YU6v(jG??acsC(dQ!;{o@v~aaEh$J-U{9b3K)iu!&H0%18;-WQNld zy#?Qh;U!A!iONSl=es5=7;EqWVoo-TCdDr4q6+rYcbEXX*krpoxi61ilL$6$ts4!3 z0ESbi;n9;>J5UQ`-zRcEXY(n545RXUFkzHpKb9u+Cf+cIah@mNK{6_$+#(q22sv-# zh&M5C0ItP_ZFNUsVtrwKaZprS4hkh^W89W$X_RXG(}WN*YzGr&;=IY5lP`d8Bc^IN zi$ovclm*GB5kbG*VTSmDxJZ98VguLvQ9RuLTyfVZ{BcQHJU(5G%4oA+ zYu*aS0Zf}W8c>nnd9|eC6*}Pui-(HE!V2y-OIA7Uwo+p|{aS+I63SOA= znhWN;u%xdQnwypLQ;5pU#Nv1Gh6zN))tY9qs^=i4eB)4!mlju9Dr<{GU1Mv{YNVes zFXaK9+p=L~20L4{9n9cTXV7*qr(XUPu?)`VMX0lf2#>-F!~se_dtf$)u^)E=bX6jx z>H0uY9(efuc3ucLi6+RiH2aHRVSb+nFTMR~-KxmV8>V-~Q!&lG=6&QD!JxNFz~+UI z&TN7LhFK5NrqPhXoIv4Op}pr?H5UqqZtlCaLg}`xa-N&$zU{=@3a!zzxXT3!b}iHy z$}K4nP3I89poyy_>4@cQjrK76uZKML*53-6f6C_zbwTGJ#r)r|Qi9_Xdre$o7$PJR zAxROv67inhr1eP|f=UeRrJIFU%?K3CR;%y5-s_tWl7F;KfuC>+!ntF~Z-!8AAzjzE z)GJ#F`ZHzzgOF6r_%OtSwi?TL&}y?h9ldNpZ8@)E*85juDp`I)2}jgI z`x)Y!<64d6O&J}O_nK+)XWx|so+LKo4;MZev-ez-1AdtQc{wms#TFmKUq?xSmxlvL`r=)} zvGwD1xmn*Z@lf@4Ah&zV9-AI2PMg*{+E(CF&lni;9K@DJ56|3;p;vsR-qT?G()BU+ z%y+4SxJ-J~paJ~6NBi>+ALd8WDedlPpVvEX&j<|6zhc(Nf{!k- zANayG+zi{|q->Y}o2|_Ukv}C;&%4u3uY_ogcL4Vq9d=1Lq0;oSbd12C!*yWQQ5(ep z>=@xv0t1D8%XGm44$c2MlJiuYA*;3Vwplh+ct3D0Iynq~4B<9bT6cvyT!%dIW#qQ> zdi+5oFZnEj2JOo!s^8&?1f zSHK4B38#)I{W!|hIrxFKJR%;mRk{Zoqva2ho$&dPJf=Y z^KD*pVFvtP@)&;pv$l!gpW*jNvv`SBY^|(8v#-2|cKgrat4W=(#DLK2X-X{#8nV4H z7kZ=92#F+pl>6UXq8q6JB8)bkaJ0_bfk*0|3>|w_otjFHx55;+bN>i42iImTteOli z=Q3DzP`NOGs%O{pW91c75uM)4nTG}TPXuF>+=qb(j{LE4hBYGrpG|9~bj zXM;YBcEq-W!(!DUxSq>BAmHu*bc*m&v@M#N{c@wp8SQD6%mV-3K(2mI?it50E!X#5 z=ge!jyyM4011`vH;_pT$PP>%<2~==r;w= z%ZaL;L`5s9m;abkQz>b(JH*#7q&^=jZH$oR$+iF}Y*XAGsLd zy;j})NZp+;p=;Lfih{p%bFdHM%Hz|IBwMtG@W%N!q0limIRms5uSUjUa*sC5%0lXc z4RSeXVQ92O-PhVNoDmP;Ck{a?1EES^e`1|ZG9=`lIQq$B^7kd#TnH?_RSFQF*x@pF z96M@{>A{D)(Odg7L2W;xoBN>{q%+jS7Pb)~zWwdHp#@VCp4XuUVgsAIUX3I1bd8{~RT5w5d6fO8CmGCJBE<>4-a~;Q)Y{(Mg zM3)9)Lzl#!EnNV(RVuOUWT%j~-2MCWb6+@)mhW$XG<~gf{lnnKWs-?259y8oBTF1b z%zZa$fH0rn-t@e?8n|5{i=t7Bd~l#5HkH#hPxy{|mmFX74X!L6Zm$;GsK>h|_*Y@G zyPS_rHSNNdUgy=+MnwPCsU7HI>yj6BmJ?I(otj9F^nHnjy(t7oN^lkW<{`kx03ZgB1r2yXkJ3h9T(i&E=}) z)TMi|sR~uIdFQE1y(=G24u^?xyzOVrkX5Q|OBNfRnMh0U)s0f}=#h))%CH%W6f+{G>_5rfH=pj7h7fQ!r?IcY ztL2rE*2Ka;P$j7}t=w~i3v2x`P4rFa*JakzJv~8j5X!DAqve$Q2#=fQT(woDt>Oa( z8W!ZMA2>nGll#A>H+ulVx+R^whh<-!hJH0rRssrOxy@{errfRE#YXY3`yv!L*VqXm zvC)}DaSttKiDkJ`Wb8Qj0N5d*l0a>J5~K@)kXn<_DOBqT!T^>^Hrw$#a)@kB2{QpP z)ia)RY#YH()FJb3o{h8TeZq*r`VtHEkEQ(5b0>VSo8DxzDMbjI>iTvro)!!DPoHLW zbLFaM{)jGhr3;uI#O3bnDu{xOr`<(-r~A0~XK)xr{`c8t0-(~$N7YHNA1C1?YY_r( z(f`D!yRwgADq@t!v~S}<75;jGH+y|tv-j_rpz~`fm`eQXQ3WzJn^-Sqd8q6p)uQjT zRAbB8jl77lh2N!M8O)e~l(K`DWwFh$vxm5lFU$_jrT*+OaUDaYXZ7#n-}l6rJ>F!> zbPk_8woTtok4iv~a@;=yOgrM{Z)3rUKS@*?iZu!^MGhVXSIa}=sO3srG^%0DN*0`v zn9y%sE|bp>on2;Tsx|;dudxoss*a4D#itz))r!RTyS66s@*W&BkS63%*`p};O(`Ov z+_FnUR)!8=%>2#_@il3ejSuBLUxPf!k(^ZQ0HdNHVu#olRTk&W`a<(|ipi!Mues;KDSu52U54CXk*u()&QP?w7`Ty#36w)tEq1x)V_wX3zVH$ zme;)uIW5&8L$#BN%m>=6T+b6<^LUi;E0QB;c3Pc#Kzi|F?5}!0vQI5ZhNWSd4tM*p z)Cz0MrY`I;GpMzVHLz-y+d(JUxo`$>)B7Kbqiz7DV1ADbEc*b1$OYog`$7wEbY*0B zyiT5)e6Ws)dEHlzi?6PYdW6v=uW{`B_RR^3ck9IGPG8*a358Ye{OX;%`9th*>&5CQ zd0bpceQH55oaM6uJ{Nr zj12nA*cY|1&S!W$dgS}6pyejSny$2KQFMSpfdo?VS39hHsbMkbp&E>YPeRgujRBPV zBN;k9cQR{-f5#trKpStiMLyg>V(8Sujoz(QxAWGJPywt;c$W5>5=xI90_;bLgpIrA z$B-xzy8Pa&mvX|Pgn0*1s<#AZzu9w6EZom6h97A!8*~tF$RwOjyDgeHkEHbLJ9E>^ zlS6^UAmV=3Vf`==GK*Z?&E@DpYuV_wlw_9YumvUP z3n@Zk2o71lA^ex?IQkR*=(P4-lkBBF-Hl$or@{)#QsEPl>m-@XR5Je|uWPZrqY}IQ z!*ONA%_xp_xB|EXq?3ay5{j1hTjRbD56^uL}NwXYzsmzgyY?~*=n}4K0u;8yTAr;U$9%i{dx~R@`0<7;cMRQ zIB6L*RKPn6d^?giY) zoBbY@(w*_K!bkjSCA|>NX$7S$w+_FiR0a z3c2PQ()bl_t)MrOl>izE1Cx)5+BC7ZKF6)S*ZL?Z>l8$7dDgA=Gc!i2&23Fj_46pNuW8Q)@tLW)+ov zOu(>8P8-QNSO)&4UdWqT!b%G>cHJLredhM1 zf-<}`C$L7`h{{X3G0p!vaoxjuuHxpC2#aJ63s}DXdHMCA0vqChC^f0SM$5C)zJ!(F zAR(N^*`FHg&X(v%OYF+it9cZC@fN4McrW}qxE zYs-Pdc=ckc@FYh(<>_n^^R(R2U_=5tKJq>7A4Tb`APo7g_W@hamOoQ+;Q+$U4(oi+ z)6Q(^w)Q?r9wA~&STcq`k4Y)na1Lt;$p7@t^OhqkWmuka7-6hb&hU2CR9T=O`FdH{g*$0TpRRQ-ikkiNU>$^Yt*LN>? zqijBK5J&8%@$4pU(b;FGAPzbp8O(vARac8{A;~Tj<*wE58NJ3*R+WekvfJ3wFf#+)TXezx8rZf)8WXazj95@6 z6{ON4l6Z!9Bhw>Dkg`%t^JOZCOY7Be!4oSpfT6%f6y(bF40OYPEQ6&*3 z_7-mn77gQ}IkQ3|(Qe@GD*~Dw!2@K8@DK+v`ND3$X_>#?$^ZHRRl>2Tl{SO)84z^3y(H7(h->4n=-5uE;z}BeUMk2{ z)Pn3c9=+7$GiuV!e|_!NsiY0B#C{T9Lx`XzwJ0K_r2;nH+a}>_q#dtJKBk z741N439ozhuG};Abl${Yyl%Tgt>M2~H*`DQxOpa?$QsQeWHiIgs2hh_b9FVwV_yww z+-?j%qPxhM2tO&=)&Oqh#_W0IbxKGd#4vVD5)ENL8DjNua>w<}V5KSTuM+t;@)<XVKFC3zLRB_6gJI1j71Ejs~Md9 znrIvUyyJ5>@a|K9dGWtLwjW+Una(m5$e$(Q>LBO>4|e&N@*Q+&pIj)a@=oQa9yR`c zSYL2&l;c1_)f7;4I}}v!S%nGxET4i@EOt}jPRB?l$!nL$P&1)c{-sVt*wHNEbq8~Z z*kq$h6l7>c30;q&KHS<17L4_o{V>QY;<9AgKfuW7`kF2tiD7--b{DB@OU zg<#eL6*mc)85(5;hk?SAO)s!QL7fTgBPXn0PzTFo3=3{G{SjB~B#dcdZBt4qolMvd zKXWGRfCE3AV;$1ebvG?RqJC=hkioi`*%G+gMFV;W8eBl{Ko;lvbKHtmr+;Y8gv$tnogrVdwSP z$;vo|WLQv!udc`x3=0t67!R*DVYJ2q%W!wxyjvkz^Pf4hWj{A=M<`FU;9R(*h0M~f`A@Pi0U`bD)n3sEsXeB?C zJJk$3ho$0xmb!oWCz=v!5OIeriWmWQRf$z+f=B1pWwkqMq6|E?Kkm4aXk*;M0myhx z7VKG@A!g<%a4GKyI*&z?WlPwT$xwt9e=Vx~Rx2hq)nc`eZ9%VNTa0E;uTr9F@>lCC zM#=hjSwSynHW*$WB=km8JyrKS89Af90~L!Jq#*a~Va)7~uhBNnYy?3j))Zy74rerh zuB6gjOP4K3>2#5*2cx43k#*#i`mpG{KaZetzq8o8hJ_^-95TeI3nkYO82e2Zi3a@o zrQ5`^5irjnZ}K4RRG`h`*W!nOg4y&wZIuNc_No<)oz~d1dXpChnafa~Y%U zCoOtfpLhzn(}-l&7r-_vG>Df13G=X#6r3^_-+x@%c@*ew)T&ALLEG;=0fGo3y?XgX#X;N;u~Wxf-NRUw2o~N*oo_;Aani^ zS1XG=$ud?7j#up#X1`id3T532`>L_8SO4Oa5Oj_1b>c~7)5tA>#EE~t_F2R8?4!(? zIJ{E%d94-t{fuCut>j|Twon-5$$Nvt+-7D%H>Vzb8ZDm0 zR~=_^S4lX^p$8_h2Q}s#A60j{xL%rU2gw7%whB`>Ez{T`F|?T^Q7`m#+Z-u%Oq=?p zBKjp8x}zJ+ED8OY2-LZDx}<%D4dE(X)LLeDRYr$KOPVYg1h&|u8a@VqlPj6@Rl-f7UCd~eZ5&8>g)V`EpXp(!Bw0J55B04apz zA8rtke}fB#m@#JV7T($%K08T<>!T*qatqIA{_Ltz3$Alab82_-3M_Z3X_Kx%;%@o3 z;#s>t5X*6`%AHZ91>aF6Go;X8d9D 0 - }).map(function(a) { + + return form.querySelector('#txtAlbumArtist').value.trim().split(';').filter(function (s) { + + return s.length > 0; + + }).map(function (a) { + return { Name: a - } - }) + }; + }); } function getArtists(form) { - return form.querySelector("#txtArtist").value.trim().split(";").filter(function(s) { - return s.length > 0 - }).map(function(a) { + + return form.querySelector('#txtArtist').value.trim().split(';').filter(function (s) { + + return s.length > 0; + + }).map(function (a) { + return { Name: a - } - }) + }; + }); } function getDateValue(form, element, property) { + var val = form.querySelector(element).value; - if (!val) return null; + + if (!val) { + return null; + } + if (currentItem[property]) { - var date = datetime.parseISO8601Date(currentItem[property], !0), - parts = date.toISOString().split("T"); - if (0 === parts[0].indexOf(val)) { - val += "T" + parts[1] + + var date = datetime.parseISO8601Date(currentItem[property], true); + + var parts = date.toISOString().split('T'); + + // If the date is the same, preserve the time + if (parts[0].indexOf(val) === 0) { + + var iso = parts[1]; + + val += 'T' + iso; } } - return val + + return val; } function onSubmit(e) { + loading.show(); - var form = this, - item = { - Id: currentItem.Id, - Name: form.querySelector("#txtName").value, - OriginalTitle: form.querySelector("#txtOriginalName").value, - ForcedSortName: form.querySelector("#txtSortName").value, - CommunityRating: form.querySelector("#txtCommunityRating").value, - CriticRating: form.querySelector("#txtCriticRating").value, - IndexNumber: form.querySelector("#txtIndexNumber").value || null, - AirsBeforeSeasonNumber: form.querySelector("#txtAirsBeforeSeason").value, - AirsAfterSeasonNumber: form.querySelector("#txtAirsAfterSeason").value, - AirsBeforeEpisodeNumber: form.querySelector("#txtAirsBeforeEpisode").value, - ParentIndexNumber: form.querySelector("#txtParentIndexNumber").value || null, - DisplayOrder: form.querySelector("#selectDisplayOrder").value, - Album: form.querySelector("#txtAlbum").value, - AlbumArtists: getAlbumArtists(form), - ArtistItems: getArtists(form), - Overview: form.querySelector("#txtOverview").value, - Status: form.querySelector("#selectStatus").value, - AirDays: getSelectedAirDays(form), - AirTime: form.querySelector("#txtAirTime").value, - Genres: getListValues(form.querySelector("#listGenres")), - Tags: getListValues(form.querySelector("#listTags")), - Studios: getListValues(form.querySelector("#listStudios")).map(function(element) { - return { - Name: element - } - }), - PremiereDate: getDateValue(form, "#txtPremiereDate", "PremiereDate"), - DateCreated: getDateValue(form, "#txtDateAdded", "DateCreated"), - EndDate: getDateValue(form, "#txtEndDate", "EndDate"), - ProductionYear: form.querySelector("#txtProductionYear").value, - AspectRatio: form.querySelector("#txtOriginalAspectRatio").value, - Video3DFormat: form.querySelector("#select3dFormat").value, - OfficialRating: form.querySelector("#selectOfficialRating").value, - CustomRating: form.querySelector("#selectCustomRating").value, - People: currentItem.People, - LockData: form.querySelector("#chkLockData").checked, - LockedFields: Array.prototype.filter.call(form.querySelectorAll(".selectLockedField"), function(c) { - return !c.checked - }).map(function(c) { - return c.getAttribute("data-value") - }) - }; + + var form = this; + + var item = { + Id: currentItem.Id, + Name: form.querySelector('#txtName').value, + OriginalTitle: form.querySelector('#txtOriginalName').value, + ForcedSortName: form.querySelector('#txtSortName').value, + CommunityRating: form.querySelector('#txtCommunityRating').value, + CriticRating: form.querySelector('#txtCriticRating').value, + IndexNumber: form.querySelector('#txtIndexNumber').value || null, + AirsBeforeSeasonNumber: form.querySelector('#txtAirsBeforeSeason').value, + AirsAfterSeasonNumber: form.querySelector('#txtAirsAfterSeason').value, + AirsBeforeEpisodeNumber: form.querySelector('#txtAirsBeforeEpisode').value, + ParentIndexNumber: form.querySelector('#txtParentIndexNumber').value || null, + DisplayOrder: form.querySelector('#selectDisplayOrder').value, + Album: form.querySelector('#txtAlbum').value, + AlbumArtists: getAlbumArtists(form), + ArtistItems: getArtists(form), + Overview: form.querySelector('#txtOverview').value, + Status: form.querySelector('#selectStatus').value, + AirDays: getSelectedAirDays(form), + AirTime: form.querySelector('#txtAirTime').value, + Genres: getListValues(form.querySelector("#listGenres")), + Tags: getListValues(form.querySelector("#listTags")), + Studios: getListValues(form.querySelector("#listStudios")).map(function (element) { return { Name: element }; }), + + PremiereDate: getDateValue(form, '#txtPremiereDate', 'PremiereDate'), + DateCreated: getDateValue(form, '#txtDateAdded', 'DateCreated'), + EndDate: getDateValue(form, '#txtEndDate', 'EndDate'), + ProductionYear: form.querySelector('#txtProductionYear').value, + AspectRatio: form.querySelector('#txtOriginalAspectRatio').value, + Video3DFormat: form.querySelector('#select3dFormat').value, + + OfficialRating: form.querySelector('#selectOfficialRating').value, + CustomRating: form.querySelector('#selectCustomRating').value, + People: currentItem.People, + LockData: form.querySelector("#chkLockData").checked, + LockedFields: Array.prototype.filter.call(form.querySelectorAll('.selectLockedField'), function (c) { + return !c.checked; + }).map(function (c) { + return c.getAttribute('data-value'); + }) + }; + item.ProviderIds = Object.assign({}, currentItem.ProviderIds); - var idElements = form.querySelectorAll(".txtExternalId"); - if (Array.prototype.map.call(idElements, function(idElem) { - var providerKey = idElem.getAttribute("data-providerkey"); - item.ProviderIds[providerKey] = idElem.value - }), item.PreferredMetadataLanguage = form.querySelector("#selectLanguage").value, item.PreferredMetadataCountryCode = form.querySelector("#selectCountry").value, "Person" === currentItem.Type) { - var placeOfBirth = form.querySelector("#txtPlaceOfBirth").value; - item.ProductionLocations = placeOfBirth ? [placeOfBirth] : [] + + var idElements = form.querySelectorAll('.txtExternalId'); + Array.prototype.map.call(idElements, function (idElem) { + var providerKey = idElem.getAttribute('data-providerkey'); + item.ProviderIds[providerKey] = idElem.value; + }); + + item.PreferredMetadataLanguage = form.querySelector('#selectLanguage').value; + item.PreferredMetadataCountryCode = form.querySelector('#selectCountry').value; + + if (currentItem.Type === "Person") { + + var placeOfBirth = form.querySelector('#txtPlaceOfBirth').value; + + item.ProductionLocations = placeOfBirth ? [placeOfBirth] : []; } - if ("Series" === currentItem.Type) { - var seriesRuntime = form.querySelector("#txtSeriesRuntime").value; - item.RunTimeTicks = seriesRuntime ? 6e8 * seriesRuntime : null + + if (currentItem.Type === "Series") { + + // 600000000 + var seriesRuntime = form.querySelector('#txtSeriesRuntime').value; + item.RunTimeTicks = seriesRuntime ? (seriesRuntime * 600000000) : null; } - var tagline = form.querySelector("#txtTagline").value; - return item.Taglines = tagline ? [tagline] : [], submitUpdatedItem(form, item), e.preventDefault(), e.stopPropagation(), !1 + + var tagline = form.querySelector('#txtTagline').value; + item.Taglines = tagline ? [tagline] : []; + + submitUpdatedItem(form, item); + + e.preventDefault(); + e.stopPropagation(); + + // Disable default form submission + return false; } function getListValues(list) { - return Array.prototype.map.call(list.querySelectorAll(".textValue"), function(el) { - return el.textContent - }) + return Array.prototype.map.call(list.querySelectorAll('.textValue'), function (el) { return el.textContent; }); } function addElementToList(source, sortCallback) { - require(["prompt"], function(prompt) { + require(['prompt'], function (prompt) { + prompt({ - label: "Value:" - }).then(function(text) { - var list = dom.parentWithClass(source, "editableListviewContainer").querySelector(".paperList"), - items = getListValues(list); - items.push(text), populateListView(list, items, sortCallback) - }) - }) + label: 'Value:' + }).then(function (text) { + var list = dom.parentWithClass(source, 'editableListviewContainer').querySelector('.paperList'); + var items = getListValues(list); + items.push(text); + populateListView(list, items, sortCallback); + }); + }); } function removeElementFromList(source) { - var el = dom.parentWithClass(source, "listItem"); - el.parentNode.removeChild(el) + var el = dom.parentWithClass(source, 'listItem'); + el.parentNode.removeChild(el); } function editPerson(context, person, index) { - require(["personEditor"], function(personEditor) { - personEditor.show(person).then(function(updatedPerson) { - -1 === index && currentItem.People.push(updatedPerson), populatePeople(context, currentItem.People) - }) - }) + + require(['personEditor'], function (personEditor) { + + personEditor.show(person).then(function (updatedPerson) { + + var isNew = index === -1; + + if (isNew) { + currentItem.People.push(updatedPerson); + } + + populatePeople(context, currentItem.People); + }); + }); } function showMoreMenu(context, button, user) { - require(["itemContextMenu"], function(itemContextMenu) { + + require(['itemContextMenu'], function (itemContextMenu) { + var item = currentItem; + itemContextMenu.show({ + item: item, positionTo: button, - edit: !1, - editImages: !0, - editSubtitles: !0, - sync: !1, - share: !1, - play: !1, - queue: !1, + edit: false, + editImages: true, + editSubtitles: true, + sync: false, + share: false, + play: false, + queue: false, user: user - }).then(function(result) { - result.deleted ? afterDeleted(context, item) : result.updated && reload(context, item.Id, item.ServerId) - }) - }) + + }).then(function (result) { + + if (result.deleted) { + afterDeleted(context, item); + + } else if (result.updated) { + reload(context, item.Id, item.ServerId); + } + }); + }); } function afterDeleted(context, item) { + var parentId = item.ParentId || item.SeasonId || item.SeriesId; - parentId ? reload(context, parentId, item.ServerId) : require(["appRouter"], function(appRouter) { - appRouter.goHome() - }) + + if (parentId) { + reload(context, parentId, item.ServerId); + } else { + require(['appRouter'], function (appRouter) { + appRouter.goHome(); + }); + } } function onEditorClick(e) { - var btnRemoveFromEditorList = dom.parentWithClass(e.target, "btnRemoveFromEditorList"); - if (btnRemoveFromEditorList) return void removeElementFromList(btnRemoveFromEditorList); - var btnAddTextItem = dom.parentWithClass(e.target, "btnAddTextItem"); - btnAddTextItem && addElementToList(btnAddTextItem) + + var btnRemoveFromEditorList = dom.parentWithClass(e.target, 'btnRemoveFromEditorList'); + if (btnRemoveFromEditorList) { + removeElementFromList(btnRemoveFromEditorList); + return; + } + + var btnAddTextItem = dom.parentWithClass(e.target, 'btnAddTextItem'); + if (btnAddTextItem) { + addElementToList(btnAddTextItem); + } } function getApiClient() { - return connectionManager.getApiClient(currentItem.ServerId) + return connectionManager.getApiClient(currentItem.ServerId); } function init(context, apiClient) { - context.querySelector(".externalIds").addEventListener("click", function(e) { - var btnOpenExternalId = dom.parentWithClass(e.target, "btnOpenExternalId"); + + context.querySelector('.externalIds').addEventListener('click', function (e) { + var btnOpenExternalId = dom.parentWithClass(e.target, 'btnOpenExternalId'); if (btnOpenExternalId) { - var field = context.querySelector("#" + btnOpenExternalId.getAttribute("data-fieldid")), - formatString = field.getAttribute("data-formatstring"); - field.value && shell.openUrl(formatString.replace("{0}", field.value)) + var field = context.querySelector('#' + btnOpenExternalId.getAttribute('data-fieldid')); + + var formatString = field.getAttribute('data-formatstring'); + + if (field.value) { + shell.openUrl(formatString.replace('{0}', field.value)); + } } - }), context.querySelector(".btnCancel").addEventListener("click", function() { - closeDialog(!1) - }), context.querySelector(".btnMore").addEventListener("click", function(e) { - getApiClient().getCurrentUser().then(function(user) { - showMoreMenu(context, e.target, user) - }) - }), context.querySelector(".btnHeaderSave").addEventListener("click", function(e) { - context.querySelector(".btnSave").click() - }), context.querySelector("#chkLockData").addEventListener("click", function(e) { - e.target.checked ? hideElement(".providerSettingsContainer") : showElement(".providerSettingsContainer") - }), context.removeEventListener("click", onEditorClick), context.addEventListener("click", onEditorClick); - var form = context.querySelector("form"); - form.removeEventListener("submit", onSubmit), form.addEventListener("submit", onSubmit), context.querySelector("#btnAddPerson").addEventListener("click", function(event, data) { - editPerson(context, {}, -1) - }), context.querySelector("#peopleList").addEventListener("click", function(e) { - var index, btnDeletePerson = dom.parentWithClass(e.target, "btnDeletePerson"); - btnDeletePerson && (index = parseInt(btnDeletePerson.getAttribute("data-index")), currentItem.People.splice(index, 1), populatePeople(context, currentItem.People)); - var btnEditPerson = dom.parentWithClass(e.target, "btnEditPerson"); - btnEditPerson && (index = parseInt(btnEditPerson.getAttribute("data-index")), editPerson(context, currentItem.People[index], index)) - }) + }); + + context.querySelector('.btnCancel').addEventListener('click', function () { + + closeDialog(false); + }); + + context.querySelector('.btnMore').addEventListener('click', function (e) { + + getApiClient().getCurrentUser().then(function (user) { + showMoreMenu(context, e.target, user); + }); + + }); + + context.querySelector('.btnHeaderSave').addEventListener('click', function (e) { + + context.querySelector('.btnSave').click(); + }); + + context.querySelector('#chkLockData').addEventListener('click', function (e) { + + if (!e.target.checked) { + showElement('.providerSettingsContainer'); + } else { + hideElement('.providerSettingsContainer'); + } + }); + + context.removeEventListener('click', onEditorClick); + context.addEventListener('click', onEditorClick); + + var form = context.querySelector('form'); + form.removeEventListener('submit', onSubmit); + form.addEventListener('submit', onSubmit); + + context.querySelector("#btnAddPerson").addEventListener('click', function (event, data) { + + editPerson(context, {}, -1); + }); + + context.querySelector('#peopleList').addEventListener('click', function (e) { + + var index; + var btnDeletePerson = dom.parentWithClass(e.target, 'btnDeletePerson'); + if (btnDeletePerson) { + index = parseInt(btnDeletePerson.getAttribute('data-index')); + currentItem.People.splice(index, 1); + populatePeople(context, currentItem.People); + } + + var btnEditPerson = dom.parentWithClass(e.target, 'btnEditPerson'); + if (btnEditPerson) { + index = parseInt(btnEditPerson.getAttribute('data-index')); + editPerson(context, currentItem.People[index], index); + } + }); } function getItem(itemId, serverId) { + var apiClient = connectionManager.getApiClient(serverId); - return itemId ? apiClient.getItem(apiClient.getCurrentUserId(), itemId) : apiClient.getRootFolder(apiClient.getCurrentUserId()) + + if (itemId) { + return apiClient.getItem(apiClient.getCurrentUserId(), itemId); + } + + return apiClient.getRootFolder(apiClient.getCurrentUserId()); } function getEditorConfig(itemId, serverId) { + var apiClient = connectionManager.getApiClient(serverId); - return itemId ? apiClient.getJSON(apiClient.getUrl("Items/" + itemId + "/MetadataEditor")) : Promise.resolve({}) + + if (itemId) { + return apiClient.getJSON(apiClient.getUrl('Items/' + itemId + '/MetadataEditor')); + } + + return Promise.resolve({}); } function populateCountries(select, allCountries) { + var html = ""; + html += ""; + for (var i = 0, length = allCountries.length; i < length; i++) { + var culture = allCountries[i]; - html += "" + + html += ""; } - select.innerHTML = html + + select.innerHTML = html; } function populateLanguages(select, languages) { + var html = ""; + html += ""; + for (var i = 0, length = languages.length; i < length; i++) { + var culture = languages[i]; - html += "" + + html += ""; } - select.innerHTML = html + + select.innerHTML = html; } function renderContentTypeOptions(context, metadataInfo) { - metadataInfo.ContentTypeOptions.length ? showElement("#fldContentType", context) : hideElement("#fldContentType", context); - var html = metadataInfo.ContentTypeOptions.map(function(i) { - return '" - }).join(""), - selectEl = context.querySelector("#selectContentType"); - selectEl.innerHTML = html, selectEl.value = metadataInfo.ContentType || "" + + if (!metadataInfo.ContentTypeOptions.length) { + hideElement('#fldContentType', context); + } else { + showElement('#fldContentType', context); + } + + var html = metadataInfo.ContentTypeOptions.map(function (i) { + + + return ''; + + }).join(''); + + var selectEl = context.querySelector('#selectContentType'); + selectEl.innerHTML = html; + selectEl.value = metadataInfo.ContentType || ''; } function loadExternalIds(context, item, externalIds) { - for (var html = "", providerIds = item.ProviderIds || {}, i = 0, length = externalIds.length; i < length; i++) { - var idInfo = externalIds[i], - id = "txt1" + idInfo.Key, - formatString = idInfo.UrlFormatString || "", - labelText = globalize.translate("sharedcomponents#LabelDynamicExternalId").replace("{0}", idInfo.Name); - html += '
', html += '
'; - var value = providerIds[idInfo.Key] || ""; - html += '
', html += '', html += "
", formatString && (html += ''), html += "
", html += "
" + + var html = ''; + + var providerIds = item.ProviderIds || {}; + + for (var i = 0, length = externalIds.length; i < length; i++) { + + var idInfo = externalIds[i]; + + var id = "txt1" + idInfo.Key; + var formatString = idInfo.UrlFormatString || ''; + + var labelText = globalize.translate('sharedcomponents#LabelDynamicExternalId').replace('{0}', idInfo.Name); + + html += '
'; + html += '
'; + + var value = providerIds[idInfo.Key] || ''; + + html += '
'; + html += ''; + html += '
'; + + if (formatString) { + html += ''; + } + html += '
'; + + html += '
'; + } + + var elem = context.querySelector('.externalIds', context); + elem.innerHTML = html; + + if (externalIds.length) { + context.querySelector('.externalIdsSection').classList.remove('hide'); + } else { + context.querySelector('.externalIdsSection').classList.add('hide'); } - context.querySelector(".externalIds", context).innerHTML = html, externalIds.length ? context.querySelector(".externalIdsSection").classList.remove("hide") : context.querySelector(".externalIdsSection").classList.add("hide") } + // Function to hide the element by selector or raw element + // Selector can be an element or a selector string + // Context is optional and restricts the querySelector to the context function hideElement(selector, context, multiple) { - if (context = context || document, "string" == typeof selector) { + context = context || document; + if (typeof selector === 'string') { + var elements = multiple ? context.querySelectorAll(selector) : [context.querySelector(selector)]; - Array.prototype.forEach.call(elements, function(el) { - el && el.classList.add("hide") - }) - } else selector.classList.add("hide") + + Array.prototype.forEach.call(elements, function (el) { + if (el) { + el.classList.add('hide'); + } + }); + } else { + selector.classList.add('hide'); + } } + // Function to show the element by selector or raw element + // Selector can be an element or a selector string + // Context is optional and restricts the querySelector to the context function showElement(selector, context, multiple) { - if (context = context || document, "string" == typeof selector) { + context = context || document; + if (typeof selector === 'string') { + var elements = multiple ? context.querySelectorAll(selector) : [context.querySelector(selector)]; - Array.prototype.forEach.call(elements, function(el) { - el && el.classList.remove("hide") - }) - } else selector.classList.remove("hide") + + Array.prototype.forEach.call(elements, function (el) { + if (el) { + el.classList.remove('hide'); + } + }); + } else { + selector.classList.remove('hide'); + } } function setFieldVisibilities(context, item) { - item.Path && !1 !== item.EnableMediaSourceDisplay ? showElement("#fldPath", context) : hideElement("#fldPath", context), "Series" === item.Type || "Movie" === item.Type || "Trailer" === item.Type ? showElement("#fldOriginalName", context) : hideElement("#fldOriginalName", context), "Series" === item.Type ? showElement("#fldSeriesRuntime", context) : hideElement("#fldSeriesRuntime", context), "Series" === item.Type || "Person" === item.Type ? showElement("#fldEndDate", context) : hideElement("#fldEndDate", context), "MusicAlbum" === item.Type ? showElement("#albumAssociationMessage", context) : hideElement("#albumAssociationMessage", context), "Movie" === item.Type || "Trailer" === item.Type ? showElement("#fldCriticRating", context) : hideElement("#fldCriticRating", context), "Series" === item.Type ? (showElement("#fldStatus", context), showElement("#fldAirDays", context), showElement("#fldAirTime", context)) : (hideElement("#fldStatus", context), hideElement("#fldAirDays", context), hideElement("#fldAirTime", context)), "Video" === item.MediaType && "TvChannel" !== item.Type ? showElement("#fld3dFormat", context) : hideElement("#fld3dFormat", context), "Audio" === item.Type ? showElement("#fldAlbumArtist", context) : hideElement("#fldAlbumArtist", context), "Audio" === item.Type || "MusicVideo" === item.Type ? (showElement("#fldArtist", context), showElement("#fldAlbum", context)) : (hideElement("#fldArtist", context), hideElement("#fldAlbum", context)), "Episode" === item.Type && 0 === item.ParentIndexNumber ? showElement("#collapsibleSpecialEpisodeInfo", context) : hideElement("#collapsibleSpecialEpisodeInfo", context), "Person" === item.Type || "Genre" === item.Type || "Studio" === item.Type || "GameGenre" === item.Type || "MusicGenre" === item.Type || "TvChannel" === item.Type || "Book" === item.Type ? hideElement("#peopleCollapsible", context) : showElement("#peopleCollapsible", context), "Person" === item.Type || "Genre" === item.Type || "Studio" === item.Type || "GameGenre" === item.Type || "MusicGenre" === item.Type || "TvChannel" === item.Type ? (hideElement("#fldCommunityRating", context), hideElement("#genresCollapsible", context), hideElement("#studiosCollapsible", context), "TvChannel" === item.Type ? showElement("#fldOfficialRating", context) : hideElement("#fldOfficialRating", context), hideElement("#fldCustomRating", context)) : (showElement("#fldCommunityRating", context), showElement("#genresCollapsible", context), showElement("#studiosCollapsible", context), showElement("#fldOfficialRating", context), showElement("#fldCustomRating", context)), showElement("#tagsCollapsible", context), "TvChannel" === item.Type ? (hideElement("#metadataSettingsCollapsible", context), hideElement("#fldPremiereDate", context), hideElement("#fldDateAdded", context), hideElement("#fldYear", context)) : (showElement("#metadataSettingsCollapsible", context), showElement("#fldPremiereDate", context), showElement("#fldDateAdded", context), showElement("#fldYear", context)), "TvChannel" === item.Type ? hideElement(".overviewContainer", context) : showElement(".overviewContainer", context), "Person" === item.Type ? (context.querySelector("#txtProductionYear").label(globalize.translate("sharedcomponents#LabelBirthYear")), context.querySelector("#txtPremiereDate").label(globalize.translate("sharedcomponents#LabelBirthDate")), context.querySelector("#txtEndDate").label(globalize.translate("sharedcomponents#LabelDeathDate")), showElement("#fldPlaceOfBirth")) : (context.querySelector("#txtProductionYear").label(globalize.translate("sharedcomponents#LabelYear")), context.querySelector("#txtPremiereDate").label(globalize.translate("sharedcomponents#LabelReleaseDate")), context.querySelector("#txtEndDate").label(globalize.translate("sharedcomponents#LabelEndDate")), hideElement("#fldPlaceOfBirth")), "Video" === item.MediaType && "TvChannel" !== item.Type ? showElement("#fldOriginalAspectRatio") : hideElement("#fldOriginalAspectRatio"), "Audio" === item.Type || "Episode" === item.Type || "Season" === item.Type ? (showElement("#fldIndexNumber"), "Episode" === item.Type ? context.querySelector("#txtIndexNumber").label(globalize.translate("sharedcomponents#LabelEpisodeNumber")) : "Season" === item.Type ? context.querySelector("#txtIndexNumber").label(globalize.translate("sharedcomponents#LabelSeasonNumber")) : "Audio" === item.Type ? context.querySelector("#txtIndexNumber").label(globalize.translate("sharedcomponents#LabelTrackNumber")) : context.querySelector("#txtIndexNumber").label(globalize.translate("sharedcomponents#LabelNumber"))) : hideElement("#fldIndexNumber"), "Audio" === item.Type || "Episode" === item.Type ? (showElement("#fldParentIndexNumber"), "Episode" === item.Type ? context.querySelector("#txtParentIndexNumber").label(globalize.translate("sharedcomponents#LabelSeasonNumber")) : "Audio" === item.Type ? context.querySelector("#txtParentIndexNumber").label(globalize.translate("sharedcomponents#LabelDiscNumber")) : context.querySelector("#txtParentIndexNumber").label(globalize.translate("sharedcomponents#LabelParentNumber"))) : hideElement("#fldParentIndexNumber", context), "BoxSet" === item.Type ? (showElement("#fldDisplayOrder", context), hideElement(".seriesDisplayOrderDescription", context), context.querySelector("#selectDisplayOrder").innerHTML = '") : "Series" === item.Type ? (showElement("#fldDisplayOrder", context), showElement(".seriesDisplayOrderDescription", context), context.querySelector("#selectDisplayOrder").innerHTML = '') : (context.querySelector("#selectDisplayOrder").innerHTML = "", hideElement("#fldDisplayOrder", context)) + if (item.Path && item.EnableMediaSourceDisplay !== false) { + showElement('#fldPath', context); + } else { + hideElement('#fldPath', context); + } + + if (item.Type === "Series" || item.Type === "Movie" || item.Type === "Trailer") { + showElement('#fldOriginalName', context); + } else { + hideElement('#fldOriginalName', context); + } + + if (item.Type === "Series") { + showElement('#fldSeriesRuntime', context); + } else { + hideElement('#fldSeriesRuntime', context); + } + + if (item.Type === "Series" || item.Type === "Person") { + showElement('#fldEndDate', context); + } else { + hideElement('#fldEndDate', context); + } + + if (item.Type === "MusicAlbum") { + showElement('#albumAssociationMessage', context); + } else { + hideElement('#albumAssociationMessage', context); + } + + if (item.Type === "Movie" || item.Type === "Trailer") { + showElement('#fldCriticRating', context); + } else { + hideElement('#fldCriticRating', context); + } + + if (item.Type === "Series") { + showElement('#fldStatus', context); + showElement('#fldAirDays', context); + showElement('#fldAirTime', context); + } else { + hideElement('#fldStatus', context); + hideElement('#fldAirDays', context); + hideElement('#fldAirTime', context); + } + + if (item.MediaType === "Video" && item.Type !== "TvChannel") { + showElement('#fld3dFormat', context); + } else { + hideElement('#fld3dFormat', context); + } + + if (item.Type === "Audio") { + showElement('#fldAlbumArtist', context); + } else { + hideElement('#fldAlbumArtist', context); + } + + if (item.Type === "Audio" || item.Type === "MusicVideo") { + showElement('#fldArtist', context); + showElement('#fldAlbum', context); + } else { + hideElement('#fldArtist', context); + hideElement('#fldAlbum', context); + } + + if (item.Type === "Episode" && item.ParentIndexNumber === 0) { + showElement('#collapsibleSpecialEpisodeInfo', context); + } else { + hideElement('#collapsibleSpecialEpisodeInfo', context); + } + + if (item.Type === "Person" || + item.Type === "Genre" || + item.Type === "Studio" || + item.Type === "GameGenre" || + item.Type === "MusicGenre" || + item.Type === "TvChannel" || + item.Type === "Book") { + hideElement('#peopleCollapsible', context); + } else { + showElement('#peopleCollapsible', context); + } + + if (item.Type === "Person" || item.Type === "Genre" || item.Type === "Studio" || item.Type === "GameGenre" || item.Type === "MusicGenre" || item.Type === "TvChannel") { + hideElement('#fldCommunityRating', context); + hideElement('#genresCollapsible', context); + hideElement('#studiosCollapsible', context); + + if (item.Type === "TvChannel") { + showElement('#fldOfficialRating', context); + } else { + hideElement('#fldOfficialRating', context); + } + hideElement('#fldCustomRating', context); + } else { + showElement('#fldCommunityRating', context); + showElement('#genresCollapsible', context); + showElement('#studiosCollapsible', context); + showElement('#fldOfficialRating', context); + showElement('#fldCustomRating', context); + } + + showElement('#tagsCollapsible', context); + + if (item.Type === "TvChannel") { + hideElement('#metadataSettingsCollapsible', context); + hideElement('#fldPremiereDate', context); + hideElement('#fldDateAdded', context); + hideElement('#fldYear', context); + } else { + showElement('#metadataSettingsCollapsible', context); + showElement('#fldPremiereDate', context); + showElement('#fldDateAdded', context); + showElement('#fldYear', context); + } + + if (item.Type === "TvChannel") { + hideElement('.overviewContainer', context); + } else { + showElement('.overviewContainer', context); + } + + if (item.Type === "Person") { + //todo + context.querySelector('#txtProductionYear').label(globalize.translate('sharedcomponents#LabelBirthYear')); + context.querySelector("#txtPremiereDate").label(globalize.translate('sharedcomponents#LabelBirthDate')); + context.querySelector("#txtEndDate").label(globalize.translate('sharedcomponents#LabelDeathDate')); + showElement('#fldPlaceOfBirth'); + } else { + context.querySelector('#txtProductionYear').label(globalize.translate('sharedcomponents#LabelYear')); + context.querySelector("#txtPremiereDate").label(globalize.translate('sharedcomponents#LabelReleaseDate')); + context.querySelector("#txtEndDate").label(globalize.translate('sharedcomponents#LabelEndDate')); + hideElement('#fldPlaceOfBirth'); + } + + if (item.MediaType === "Video" && item.Type !== "TvChannel") { + showElement('#fldOriginalAspectRatio'); + } else { + hideElement('#fldOriginalAspectRatio'); + } + + if (item.Type === "Audio" || item.Type === "Episode" || item.Type === "Season") { + showElement('#fldIndexNumber'); + + if (item.Type === "Episode") { + context.querySelector('#txtIndexNumber').label(globalize.translate('sharedcomponents#LabelEpisodeNumber')); + } else if (item.Type === "Season") { + context.querySelector('#txtIndexNumber').label(globalize.translate('sharedcomponents#LabelSeasonNumber')); + } else if (item.Type === "Audio") { + context.querySelector('#txtIndexNumber').label(globalize.translate('sharedcomponents#LabelTrackNumber')); + } else { + context.querySelector('#txtIndexNumber').label(globalize.translate('sharedcomponents#LabelNumber')); + } + } else { + hideElement('#fldIndexNumber'); + } + + if (item.Type === "Audio" || item.Type === "Episode") { + showElement('#fldParentIndexNumber'); + + if (item.Type === "Episode") { + context.querySelector('#txtParentIndexNumber').label(globalize.translate('sharedcomponents#LabelSeasonNumber')); + } else if (item.Type === "Audio") { + context.querySelector('#txtParentIndexNumber').label(globalize.translate('sharedcomponents#LabelDiscNumber')); + } else { + context.querySelector('#txtParentIndexNumber').label(globalize.translate('sharedcomponents#LabelParentNumber')); + } + } else { + hideElement('#fldParentIndexNumber', context); + } + + if (item.Type === "BoxSet") { + showElement('#fldDisplayOrder', context); + hideElement('.seriesDisplayOrderDescription', context); + + context.querySelector('#selectDisplayOrder').innerHTML = ''; + } else if (item.Type === "Series") { + showElement('#fldDisplayOrder', context); + showElement('.seriesDisplayOrderDescription', context); + + context.querySelector('#selectDisplayOrder').innerHTML = ''; + } else { + context.querySelector('#selectDisplayOrder').innerHTML = ''; + hideElement('#fldDisplayOrder', context); + } } function fillItemInfo(context, item, parentalRatingOptions) { - var select = context.querySelector("#selectOfficialRating"); - populateRatings(parentalRatingOptions, select, item.OfficialRating), select.value = item.OfficialRating || "", select = context.querySelector("#selectCustomRating"), populateRatings(parentalRatingOptions, select, item.CustomRating), select.value = item.CustomRating || ""; - var selectStatus = context.querySelector("#selectStatus"); - populateStatus(selectStatus), selectStatus.value = item.Status || "", context.querySelector("#select3dFormat", context).value = item.Video3DFormat || "", Array.prototype.forEach.call(context.querySelectorAll(".chkAirDay", context), function(el) { - el.checked = -1 !== (item.AirDays || []).indexOf(el.getAttribute("data-day")) - }), populateListView(context.querySelector("#listGenres"), item.Genres), populatePeople(context, item.People || []), populateListView(context.querySelector("#listStudios"), (item.Studios || []).map(function(element) { - return element.Name || "" - })), populateListView(context.querySelector("#listTags"), item.Tags); - var lockData = item.LockData || !1, - chkLockData = context.querySelector("#chkLockData"); - chkLockData.checked = lockData, chkLockData.checked ? hideElement(".providerSettingsContainer", context) : showElement(".providerSettingsContainer", context), fillMetadataSettings(context, item, item.LockedFields), context.querySelector("#txtPath").value = item.Path || "", context.querySelector("#txtName").value = item.Name || "", context.querySelector("#txtOriginalName").value = item.OriginalTitle || "", context.querySelector("#txtOverview").value = item.Overview || "", context.querySelector("#txtTagline").value = item.Taglines && item.Taglines.length ? item.Taglines[0] : "", context.querySelector("#txtSortName").value = item.ForcedSortName || "", context.querySelector("#txtCommunityRating").value = item.CommunityRating || "", context.querySelector("#txtCriticRating").value = item.CriticRating || "", context.querySelector("#txtIndexNumber").value = null == item.IndexNumber ? "" : item.IndexNumber, context.querySelector("#txtParentIndexNumber").value = null == item.ParentIndexNumber ? "" : item.ParentIndexNumber, context.querySelector("#txtAirsBeforeSeason").value = "AirsBeforeSeasonNumber" in item ? item.AirsBeforeSeasonNumber : "", context.querySelector("#txtAirsAfterSeason").value = "AirsAfterSeasonNumber" in item ? item.AirsAfterSeasonNumber : "", context.querySelector("#txtAirsBeforeEpisode").value = "AirsBeforeEpisodeNumber" in item ? item.AirsBeforeEpisodeNumber : "", context.querySelector("#txtAlbum").value = item.Album || "", context.querySelector("#txtAlbumArtist").value = (item.AlbumArtists || []).map(function(a) { - return a.Name - }).join(";"), item.Type, context.querySelector("#selectDisplayOrder").value = item.DisplayOrder || "", context.querySelector("#txtArtist").value = (item.ArtistItems || []).map(function(a) { - return a.Name - }).join(";"); + + var select = context.querySelector('#selectOfficialRating'); + + populateRatings(parentalRatingOptions, select, item.OfficialRating); + + select.value = item.OfficialRating || ""; + + select = context.querySelector('#selectCustomRating'); + + populateRatings(parentalRatingOptions, select, item.CustomRating); + + select.value = item.CustomRating || ""; + + var selectStatus = context.querySelector('#selectStatus'); + populateStatus(selectStatus); + selectStatus.value = item.Status || ""; + + context.querySelector('#select3dFormat', context).value = item.Video3DFormat || ""; + + Array.prototype.forEach.call(context.querySelectorAll('.chkAirDay', context), function (el) { + el.checked = (item.AirDays || []).indexOf(el.getAttribute('data-day')) !== -1; + }); + + populateListView(context.querySelector('#listGenres'), item.Genres); + populatePeople(context, item.People || []); + + populateListView(context.querySelector('#listStudios'), (item.Studios || []).map(function (element) { return element.Name || ''; })); + + populateListView(context.querySelector('#listTags'), item.Tags); + + var lockData = (item.LockData || false); + var chkLockData = context.querySelector("#chkLockData"); + chkLockData.checked = lockData; + if (chkLockData.checked) { + hideElement('.providerSettingsContainer', context); + } else { + showElement('.providerSettingsContainer', context); + } + fillMetadataSettings(context, item, item.LockedFields); + + context.querySelector('#txtPath').value = item.Path || ''; + context.querySelector('#txtName').value = item.Name || ""; + context.querySelector('#txtOriginalName').value = item.OriginalTitle || ""; + context.querySelector('#txtOverview').value = item.Overview || ''; + context.querySelector('#txtTagline').value = (item.Taglines && item.Taglines.length ? item.Taglines[0] : ''); + context.querySelector('#txtSortName').value = item.ForcedSortName || ""; + context.querySelector('#txtCommunityRating').value = item.CommunityRating || ""; + + context.querySelector('#txtCriticRating').value = item.CriticRating || ""; + + context.querySelector('#txtIndexNumber').value = item.IndexNumber == null ? '' : item.IndexNumber; + context.querySelector('#txtParentIndexNumber').value = item.ParentIndexNumber == null ? '' : item.ParentIndexNumber; + + context.querySelector('#txtAirsBeforeSeason').value = ('AirsBeforeSeasonNumber' in item) ? item.AirsBeforeSeasonNumber : ""; + context.querySelector('#txtAirsAfterSeason').value = ('AirsAfterSeasonNumber' in item) ? item.AirsAfterSeasonNumber : ""; + context.querySelector('#txtAirsBeforeEpisode').value = ('AirsBeforeEpisodeNumber' in item) ? item.AirsBeforeEpisodeNumber : ""; + + context.querySelector('#txtAlbum').value = item.Album || ""; + + context.querySelector('#txtAlbumArtist').value = (item.AlbumArtists || []).map(function (a) { + return a.Name; + }).join(';'); + + if (item.Type === 'Series') { + context.querySelector('#selectDisplayOrder').value = item.DisplayOrder || ''; + } + else { + context.querySelector('#selectDisplayOrder').value = item.DisplayOrder || ''; + } + + context.querySelector('#txtArtist').value = (item.ArtistItems || []).map(function (a) { + return a.Name; + }).join(';'); + var date; - if (item.DateCreated) try { - date = datetime.parseISO8601Date(item.DateCreated, !0), context.querySelector("#txtDateAdded").value = date.toISOString().slice(0, 10) - } catch (e) { - context.querySelector("#txtDateAdded").value = "" - } else context.querySelector("#txtDateAdded").value = ""; - if (item.PremiereDate) try { - date = datetime.parseISO8601Date(item.PremiereDate, !0), context.querySelector("#txtPremiereDate").value = date.toISOString().slice(0, 10) - } catch (e) { - context.querySelector("#txtPremiereDate").value = "" - } else context.querySelector("#txtPremiereDate").value = ""; - if (item.EndDate) try { - date = datetime.parseISO8601Date(item.EndDate, !0), context.querySelector("#txtEndDate").value = date.toISOString().slice(0, 10) - } catch (e) { - context.querySelector("#txtEndDate").value = "" - } else context.querySelector("#txtEndDate").value = ""; - context.querySelector("#txtProductionYear").value = item.ProductionYear || "", context.querySelector("#txtAirTime").value = item.AirTime || ""; - var placeofBirth = item.ProductionLocations && item.ProductionLocations.length ? item.ProductionLocations[0] : ""; - if (context.querySelector("#txtPlaceOfBirth").value = placeofBirth, context.querySelector("#txtOriginalAspectRatio").value = item.AspectRatio || "", context.querySelector("#selectLanguage").value = item.PreferredMetadataLanguage || "", context.querySelector("#selectCountry").value = item.PreferredMetadataCountryCode || "", item.RunTimeTicks) { - var minutes = item.RunTimeTicks / 6e8; - context.querySelector("#txtSeriesRuntime").value = Math.round(minutes) - } else context.querySelector("#txtSeriesRuntime", context).value = "" + + if (item.DateCreated) { + try { + date = datetime.parseISO8601Date(item.DateCreated, true); + + context.querySelector('#txtDateAdded').value = date.toISOString().slice(0, 10); + } catch (e) { + context.querySelector('#txtDateAdded').value = ''; + } + } else { + context.querySelector('#txtDateAdded').value = ''; + } + + if (item.PremiereDate) { + try { + date = datetime.parseISO8601Date(item.PremiereDate, true); + + context.querySelector('#txtPremiereDate').value = date.toISOString().slice(0, 10); + } catch (e) { + context.querySelector('#txtPremiereDate').value = ''; + } + } else { + context.querySelector('#txtPremiereDate').value = ''; + } + + if (item.EndDate) { + try { + date = datetime.parseISO8601Date(item.EndDate, true); + + context.querySelector('#txtEndDate').value = date.toISOString().slice(0, 10); + } catch (e) { + context.querySelector('#txtEndDate').value = ''; + } + } else { + context.querySelector('#txtEndDate').value = ''; + } + + context.querySelector('#txtProductionYear').value = item.ProductionYear || ""; + + context.querySelector('#txtAirTime').value = item.AirTime || ''; + + var placeofBirth = item.ProductionLocations && item.ProductionLocations.length ? item.ProductionLocations[0] : ''; + context.querySelector('#txtPlaceOfBirth').value = placeofBirth; + + context.querySelector('#txtOriginalAspectRatio').value = item.AspectRatio || ""; + + context.querySelector('#selectLanguage').value = item.PreferredMetadataLanguage || ""; + context.querySelector('#selectCountry').value = item.PreferredMetadataCountryCode || ""; + + if (item.RunTimeTicks) { + + var minutes = item.RunTimeTicks / 600000000; + + context.querySelector('#txtSeriesRuntime').value = Math.round(minutes); + } else { + context.querySelector('#txtSeriesRuntime', context).value = ""; + } } function populateRatings(allParentalRatings, select, currentValue) { + var html = ""; + html += ""; - var i, length, rating, ratings = [], - currentValueFound = !1; - for (i = 0, length = allParentalRatings.length; i < length; i++) rating = allParentalRatings[i], ratings.push({ - Name: rating.Name, - Value: rating.Name - }), rating.Name === currentValue && (currentValueFound = !0); - for (currentValue && !currentValueFound && ratings.push({ - Name: currentValue, - Value: currentValue - }), i = 0, length = ratings.length; i < length; i++) rating = ratings[i], html += ""; - select.innerHTML = html + + var ratings = []; + var i, length, rating; + + var currentValueFound = false; + + for (i = 0, length = allParentalRatings.length; i < length; i++) { + + rating = allParentalRatings[i]; + + ratings.push({ Name: rating.Name, Value: rating.Name }); + + if (rating.Name === currentValue) { + currentValueFound = true; + } + } + + if (currentValue && !currentValueFound) { + ratings.push({ Name: currentValue, Value: currentValue }); + } + + for (i = 0, length = ratings.length; i < length; i++) { + + rating = ratings[i]; + + html += ""; + } + + select.innerHTML = html; } function populateStatus(select) { var html = ""; - html += "", html += "", html += "", select.innerHTML = html + + html += ""; + html += ""; + html += ""; + select.innerHTML = html; } function populateListView(list, items, sortCallback) { - items = items || [], void 0 === sortCallback ? items.sort(function(a, b) { - return a.toLowerCase().localeCompare(b.toLowerCase()) - }) : items = sortCallback(items); - for (var html = "", i = 0; i < items.length; i++) html += '
', html += 'live_tv', html += '
', html += '
', html += items[i], html += "
", html += "
", html += '', html += "
"; - list.innerHTML = html + + items = items || []; + if (typeof (sortCallback) === 'undefined') { + items.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); }); + } else { + items = sortCallback(items); + } + var html = ''; + for (var i = 0; i < items.length; i++) { + html += '
'; + + html += 'live_tv'; + + html += '
'; + + html += '
'; + html += items[i]; + html += '
'; + + html += '
'; + + html += ''; + + html += '
'; + } + + list.innerHTML = html; } function populatePeople(context, people) { - for (var html = "", elem = context.querySelector("#peopleList"), i = 0, length = people.length; i < length; i++) { + + var lastType = ''; + var html = ''; + + var elem = context.querySelector('#peopleList'); + + for (var i = 0, length = people.length; i < length; i++) { + var person = people[i]; - html += '
', html += 'person', html += '
', html += '", html += "
", html += '', html += "
" + + html += '
'; + + html += 'person'; + + html += '
'; + html += ''; + html += '
'; + + html += ''; + + html += '
'; } - elem.innerHTML = html + + elem.innerHTML = html; } function getLockedFieldsHtml(fields, currentFields) { - for (var html = "", i = 0; i < fields.length; i++) { - var field = fields[i], - name = field.name, - value = field.value || field.name, - checkedHtml = -1 === currentFields.indexOf(value) ? " checked" : ""; - html += "" + + var html = ''; + for (var i = 0; i < fields.length; i++) { + + var field = fields[i]; + var name = field.name; + var value = field.value || field.name; + var checkedHtml = currentFields.indexOf(value) === -1 ? ' checked' : ''; + html += ''; } - return html + return html; } function fillMetadataSettings(context, item, lockedFields) { - var container = context.querySelector(".providerSettingsContainer"); + var container = context.querySelector('.providerSettingsContainer'); lockedFields = lockedFields || []; - var lockedFieldsList = [{ - name: globalize.translate("sharedcomponents#Name"), - value: "Name" - }, { - name: globalize.translate("sharedcomponents#Overview"), - value: "Overview" - }, { - name: globalize.translate("sharedcomponents#Genres"), - value: "Genres" - }, { - name: globalize.translate("sharedcomponents#ParentalRating"), - value: "OfficialRating" - }, { - name: globalize.translate("sharedcomponents#People"), - value: "Cast" - }]; - "Person" === item.Type ? lockedFieldsList.push({ - name: globalize.translate("sharedcomponents#BirthLocation"), - value: "ProductionLocations" - }) : lockedFieldsList.push({ - name: globalize.translate("sharedcomponents#ProductionLocations"), - value: "ProductionLocations" - }), "Series" === item.Type && lockedFieldsList.push({ - name: globalize.translate("Runtime"), - value: "Runtime" - }), lockedFieldsList.push({ - name: globalize.translate("sharedcomponents#Studios"), - value: "Studios" - }), lockedFieldsList.push({ - name: globalize.translate("sharedcomponents#Tags"), - value: "Tags" - }); - var html = ""; - html += "

" + globalize.translate("sharedcomponents#HeaderEnabledFields") + "

", html += "

" + globalize.translate("sharedcomponents#HeaderEnabledFieldsHelp") + "

", html += getLockedFieldsHtml(lockedFieldsList, lockedFields), container.innerHTML = html + + var lockedFieldsList = [ + { name: globalize.translate('sharedcomponents#Name'), value: "Name" }, + { name: globalize.translate('sharedcomponents#Overview'), value: "Overview" }, + { name: globalize.translate('sharedcomponents#Genres'), value: "Genres" }, + { name: globalize.translate('sharedcomponents#ParentalRating'), value: "OfficialRating" }, + { name: globalize.translate('sharedcomponents#People'), value: "Cast" } + ]; + + if (item.Type === "Person") { + lockedFieldsList.push({ name: globalize.translate('sharedcomponents#BirthLocation'), value: "ProductionLocations" }); + } else { + lockedFieldsList.push({ name: globalize.translate('sharedcomponents#ProductionLocations'), value: "ProductionLocations" }); + } + + if (item.Type === "Series") { + lockedFieldsList.push({ name: globalize.translate('Runtime'), value: "Runtime" }); + } + + lockedFieldsList.push({ name: globalize.translate('sharedcomponents#Studios'), value: "Studios" }); + lockedFieldsList.push({ name: globalize.translate('sharedcomponents#Tags'), value: "Tags" }); + + var html = ''; + + html += "

" + globalize.translate('sharedcomponents#HeaderEnabledFields') + "

"; + html += "

" + globalize.translate('sharedcomponents#HeaderEnabledFieldsHelp') + "

"; + html += getLockedFieldsHtml(lockedFieldsList, lockedFields); + container.innerHTML = html; } function reload(context, itemId, serverId) { - loading.show(), Promise.all([getItem(itemId, serverId), getEditorConfig(itemId, serverId)]).then(function(responses) { + + loading.show(); + + Promise.all([getItem(itemId, serverId), getEditorConfig(itemId, serverId)]).then(function (responses) { + var item = responses[0]; - metadataEditorInfo = responses[1], currentItem = item; - var languages = metadataEditorInfo.Cultures, - countries = metadataEditorInfo.Countries; - renderContentTypeOptions(context, metadataEditorInfo), loadExternalIds(context, item, metadataEditorInfo.ExternalIdInfos), populateLanguages(context.querySelector("#selectLanguage"), languages), populateCountries(context.querySelector("#selectCountry"), countries), setFieldVisibilities(context, item), fillItemInfo(context, item, metadataEditorInfo.ParentalRatingOptions), "Video" === item.MediaType && "Episode" !== item.Type && "TvChannel" !== item.Type ? showElement("#fldTagline", context) : hideElement("#fldTagline", context), loading.hide() - }) + metadataEditorInfo = responses[1]; + + currentItem = item; + + var languages = metadataEditorInfo.Cultures; + var countries = metadataEditorInfo.Countries; + + renderContentTypeOptions(context, metadataEditorInfo); + + loadExternalIds(context, item, metadataEditorInfo.ExternalIdInfos); + + populateLanguages(context.querySelector('#selectLanguage'), languages); + populateCountries(context.querySelector('#selectCountry'), countries); + + setFieldVisibilities(context, item); + fillItemInfo(context, item, metadataEditorInfo.ParentalRatingOptions); + + if (item.MediaType === "Video" && item.Type !== "Episode" && item.Type !== "TvChannel") { + showElement('#fldTagline', context); + } else { + hideElement('#fldTagline', context); + } + + loading.hide(); + }); } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function show(itemId, serverId, resolve, reject) { - loading.show(), require(["text!./metadataeditor.template.html"], function(template) { + loading.show(); + + require(['text!./metadataeditor.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "medium-tall"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'medium-tall'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - var html = ""; - html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), dialogHelper.open(dlg), dlg.addEventListener("close", function() { - layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), resolve() - }), currentContext = dlg, init(dlg, connectionManager.getApiClient(serverId)), reload(dlg, itemId, serverId) - }) + + dlg.classList.add('formDialog'); + + var html = ''; + + html += globalize.translateDocument(template, 'sharedcomponents'); + + dlg.innerHTML = html; + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + + dialogHelper.open(dlg); + + dlg.addEventListener('close', function () { + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + resolve(); + }); + + currentContext = dlg; + + init(dlg, connectionManager.getApiClient(serverId)); + + reload(dlg, itemId, serverId); + }); } - var currentContext, metadataEditorInfo, currentItem; + return { - show: function(itemId, serverId) { - return new Promise(function(resolve, reject) { - return show(itemId, serverId, resolve, reject) - }) + show: function (itemId, serverId) { + return new Promise(function (resolve, reject) { + return show(itemId, serverId, resolve, reject); + }); }, - embed: function(elem, itemId, serverId) { - return new Promise(function(resolve, reject) { - loading.show(), require(["text!./metadataeditor.template.html"], function(template) { - elem.innerHTML = globalize.translateDocument(template, "sharedcomponents"), elem.querySelector(".formDialogFooter").classList.remove("formDialogFooter"), elem.querySelector(".btnHeaderSave").classList.remove("hide"), elem.querySelector(".btnCancel").classList.add("hide"), currentContext = elem, init(elem, connectionManager.getApiClient(serverId)), reload(elem, itemId, serverId), focusManager.autoFocus(elem) - }) - }) + + embed: function (elem, itemId, serverId) { + return new Promise(function (resolve, reject) { + + loading.show(); + + require(['text!./metadataeditor.template.html'], function (template) { + + elem.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + elem.querySelector('.formDialogFooter').classList.remove('formDialogFooter'); + elem.querySelector('.btnHeaderSave').classList.remove('hide'); + elem.querySelector('.btnCancel').classList.add('hide'); + + currentContext = elem; + + init(elem, connectionManager.getApiClient(serverId)); + reload(elem, itemId, serverId); + + focusManager.autoFocus(elem); + }); + }); } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/metadataeditor/personeditor.js b/src/bower_components/emby-webcomponents/metadataeditor/personeditor.js index 4bca9a2adc..7cfee43005 100644 --- a/src/bower_components/emby-webcomponents/metadataeditor/personeditor.js +++ b/src/bower_components/emby-webcomponents/metadataeditor/personeditor.js @@ -1,40 +1,99 @@ -define(["dialogHelper", "layoutManager", "globalize", "require", "paper-icon-button-light", "emby-input", "emby-select", "css!./../formdialog"], function(dialogHelper, layoutManager, globalize, require) { - "use strict"; +define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'paper-icon-button-light', 'emby-input', 'emby-select', 'css!./../formdialog'], function (dialogHelper, layoutManager, globalize, require) { + 'use strict'; function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function show(person) { - return new Promise(function(resolve, reject) { - require(["text!./personeditor.template.html"], function(template) { + return new Promise(function (resolve, reject) { + + require(['text!./personeditor.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "medium-tall"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'medium-tall'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - var html = "", - submitted = !1; - html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, dlg.querySelector(".txtPersonName", dlg).value = person.Name || "", dlg.querySelector(".selectPersonType", dlg).value = person.Type || "", dlg.querySelector(".txtPersonRole", dlg).value = person.Role || "", layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), dialogHelper.open(dlg), dlg.addEventListener("close", function() { - layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), submitted ? resolve(person) : reject() - }), dlg.querySelector(".selectPersonType").addEventListener("change", function(e) { - "Actor" === this.value ? dlg.querySelector(".fldRole").classList.remove("hide") : dlg.querySelector(".fldRole").classList.add("hide") - }), dlg.querySelector(".btnCancel").addEventListener("click", function(e) { - dialogHelper.close(dlg) - }), dlg.querySelector("form").addEventListener("submit", function(e) { - return submitted = !0, person.Name = dlg.querySelector(".txtPersonName", dlg).value, person.Type = dlg.querySelector(".selectPersonType", dlg).value, person.Role = dlg.querySelector(".txtPersonRole", dlg).value || null, dialogHelper.close(dlg), e.preventDefault(), !1 - }), dlg.querySelector(".selectPersonType").dispatchEvent(new CustomEvent("change", { - bubbles: !0 - })) - }) - }) + + dlg.classList.add('formDialog'); + + var html = ''; + var submitted = false; + + html += globalize.translateDocument(template, 'sharedcomponents'); + + dlg.innerHTML = html; + + dlg.querySelector('.txtPersonName', dlg).value = person.Name || ''; + dlg.querySelector('.selectPersonType', dlg).value = person.Type || ''; + dlg.querySelector('.txtPersonRole', dlg).value = person.Role || ''; + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + + dialogHelper.open(dlg); + + dlg.addEventListener('close', function () { + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + if (submitted) { + resolve(person); + } else { + reject(); + } + }); + + dlg.querySelector('.selectPersonType').addEventListener('change', function (e) { + + if (this.value === 'Actor') { + dlg.querySelector('.fldRole').classList.remove('hide'); + } else { + dlg.querySelector('.fldRole').classList.add('hide'); + } + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function (e) { + + dialogHelper.close(dlg); + }); + + dlg.querySelector('form').addEventListener('submit', function (e) { + + submitted = true; + + person.Name = dlg.querySelector('.txtPersonName', dlg).value; + person.Type = dlg.querySelector('.selectPersonType', dlg).value; + person.Role = dlg.querySelector('.txtPersonRole', dlg).value || null; + + dialogHelper.close(dlg); + + e.preventDefault(); + return false; + }); + + dlg.querySelector('.selectPersonType').dispatchEvent(new CustomEvent('change', { + bubbles: true + })); + }); + }); } + return { show: show - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/multidownload.js b/src/bower_components/emby-webcomponents/multidownload.js index c7554877ea..a1881b8db9 100644 --- a/src/bower_components/emby-webcomponents/multidownload.js +++ b/src/bower_components/emby-webcomponents/multidownload.js @@ -1,35 +1,66 @@ -define(["browser"], function(browser) { - "use strict"; +define(['browser'], function (browser) { + 'use strict'; function fallback(urls) { var i = 0; - ! function createIframe() { - var frame = document.createElement("iframe"); - frame.style.display = "none", frame.src = urls[i++], document.documentElement.appendChild(frame); - var interval = setInterval(function() { - "complete" !== frame.contentWindow.document.readyState && "interactive" !== frame.contentWindow.document.readyState || (clearInterval(interval), setTimeout(function() { - frame.parentNode.removeChild(frame) - }, 1e3), i < urls.length && createIframe()) - }, 100) - }() + + (function createIframe() { + var frame = document.createElement('iframe'); + frame.style.display = 'none'; + frame.src = urls[i++]; + document.documentElement.appendChild(frame); + + // the download init has to be sequential otherwise IE only use the first + var interval = setInterval(function () { + if (frame.contentWindow.document.readyState === 'complete' || frame.contentWindow.document.readyState === 'interactive') { + clearInterval(interval); + + // Safari needs a timeout + setTimeout(function () { + frame.parentNode.removeChild(frame); + }, 1000); + + if (i < urls.length) { + createIframe(); + } + } + }, 100); + })(); } function sameDomain(url) { - var a = document.createElement("a"); - return a.href = url, location.hostname === a.hostname && location.protocol === a.protocol + var a = document.createElement('a'); + a.href = url; + + return location.hostname === a.hostname && location.protocol === a.protocol; } function download(url) { - var a = document.createElement("a"); - a.download = "", a.href = url, a.dispatchEvent(new MouseEvent("click")) + var a = document.createElement('a'); + a.download = ''; + a.href = url; + // firefox doesn't support `a.click()`... + a.dispatchEvent(new MouseEvent('click')); } - return function(urls) { - if (!urls) throw new Error("`urls` required"); - if (void 0 === document.createElement("a").download) return fallback(urls); + + return function (urls) { + if (!urls) { + throw new Error('`urls` required'); + } + + if (typeof document.createElement('a').download === 'undefined') { + return fallback(urls); + } + var delay = 0; - urls.forEach(function(url) { - if (browser.firefox && !sameDomain(url)) return setTimeout(download.bind(null, url), 100 * ++delay); - download(url) - }) - } + + urls.forEach(function (url) { + // the download init has to be sequential for firefox if the urls are not on the same domain + if (browser.firefox && !sameDomain(url)) { + return setTimeout(download.bind(null, url), 100 * ++delay); + } + + download(url); + }); + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/multiselect/multiselect.css b/src/bower_components/emby-webcomponents/multiselect/multiselect.css index 42be0e86bf..2026f8aa8b 100644 --- a/src/bower_components/emby-webcomponents/multiselect/multiselect.css +++ b/src/bower_components/emby-webcomponents/multiselect/multiselect.css @@ -1,11 +1,11 @@ -.itemSelectionPanel { +.itemSelectionPanel { position: absolute; bottom: 0; left: 0; right: 0; top: 0; background-color: rgba(0, 0, 0, .3); - z-index: 99998 + z-index: 99998; } .selectionCommandsPanel { @@ -14,27 +14,22 @@ left: 0; right: 0; padding: 1em .5em; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - z-index: 99999 + z-index: 99999; } .itemSelectionCount { vertical-align: middle; color: #fff !important; - margin: 0 + margin: 0; } .multiSelectCheckboxOutline { top: 0 !important; - -webkit-border-radius: 0 !important; - border-radius: 0 !important + border-radius: 0 !important; } .withMultiSelect { - position: relative -} \ No newline at end of file + position: relative; +} diff --git a/src/bower_components/emby-webcomponents/multiselect/multiselect.js b/src/bower_components/emby-webcomponents/multiselect/multiselect.js index e22f031eb1..e720a005ae 100644 --- a/src/bower_components/emby-webcomponents/multiselect/multiselect.js +++ b/src/bower_components/emby-webcomponents/multiselect/multiselect.js @@ -1,350 +1,632 @@ -define(["browser", "appStorage", "apphost", "loading", "connectionManager", "globalize", "appRouter", "dom", "css!./multiselect"], function(browser, appStorage, appHost, loading, connectionManager, globalize, appRouter, dom) { - "use strict"; +define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'globalize', 'appRouter', 'dom', 'css!./multiselect'], function (browser, appStorage, appHost, loading, connectionManager, globalize, appRouter, dom) { + 'use strict'; + + var selectedItems = []; + var selectedElements = []; + var currentSelectionCommandsPanel; function hideSelections() { + var selectionCommandsPanel = currentSelectionCommandsPanel; if (selectionCommandsPanel) { - selectionCommandsPanel.parentNode.removeChild(selectionCommandsPanel), currentSelectionCommandsPanel = null, selectedItems = [], selectedElements = []; - for (var elems = document.querySelectorAll(".itemSelectionPanel"), i = 0, length = elems.length; i < length; i++) { + + selectionCommandsPanel.parentNode.removeChild(selectionCommandsPanel); + currentSelectionCommandsPanel = null; + + selectedItems = []; + selectedElements = []; + var elems = document.querySelectorAll('.itemSelectionPanel'); + for (var i = 0, length = elems.length; i < length; i++) { + var parent = elems[i].parentNode; - parent.removeChild(elems[i]), parent.classList.remove("withMultiSelect") + parent.removeChild(elems[i]); + parent.classList.remove('withMultiSelect'); } } } function onItemSelectionPanelClick(e, itemSelectionPanel) { - if (!dom.parentWithClass(e.target, "chkItemSelect")) { - var chkItemSelect = itemSelectionPanel.querySelector(".chkItemSelect"); - if (chkItemSelect) - if (chkItemSelect.classList.contains("checkedInitial")) chkItemSelect.classList.remove("checkedInitial"); - else { + + // toggle the checkbox, if it wasn't clicked on + if (!dom.parentWithClass(e.target, 'chkItemSelect')) { + var chkItemSelect = itemSelectionPanel.querySelector('.chkItemSelect'); + + if (chkItemSelect) { + + if (chkItemSelect.classList.contains('checkedInitial')) { + chkItemSelect.classList.remove('checkedInitial'); + } else { var newValue = !chkItemSelect.checked; - chkItemSelect.checked = newValue, updateItemSelection(chkItemSelect, newValue) + chkItemSelect.checked = newValue; + updateItemSelection(chkItemSelect, newValue); } + } } - return e.preventDefault(), e.stopPropagation(), !1 + + e.preventDefault(); + e.stopPropagation(); + return false; } function updateItemSelection(chkItemSelect, selected) { - var id = dom.parentWithAttribute(chkItemSelect, "data-id").getAttribute("data-id"); + + var id = dom.parentWithAttribute(chkItemSelect, 'data-id').getAttribute('data-id'); + if (selected) { - selectedItems.filter(function(i) { - return i === id - }).length || (selectedItems.push(id), selectedElements.push(chkItemSelect)) - } else selectedItems = selectedItems.filter(function(i) { - return i !== id - }), selectedElements = selectedElements.filter(function(i) { - return i !== chkItemSelect - }); + + var current = selectedItems.filter(function (i) { + return i === id; + }); + + if (!current.length) { + selectedItems.push(id); + selectedElements.push(chkItemSelect); + } + + } else { + selectedItems = selectedItems.filter(function (i) { + return i !== id; + }); + selectedElements = selectedElements.filter(function (i) { + return i !== chkItemSelect; + }); + } + if (selectedItems.length) { - var itemSelectionCount = document.querySelector(".itemSelectionCount"); - itemSelectionCount && (itemSelectionCount.innerHTML = selectedItems.length) - } else hideSelections() + var itemSelectionCount = document.querySelector('.itemSelectionCount'); + if (itemSelectionCount) { + itemSelectionCount.innerHTML = selectedItems.length; + } + } else { + hideSelections(); + } } function onSelectionChange(e) { - updateItemSelection(this, this.checked) + updateItemSelection(this, this.checked); } function showSelection(item, isChecked) { - var itemSelectionPanel = item.querySelector(".itemSelectionPanel"); + + var itemSelectionPanel = item.querySelector('.itemSelectionPanel'); + if (!itemSelectionPanel) { - itemSelectionPanel = document.createElement("div"), itemSelectionPanel.classList.add("itemSelectionPanel"); - var parent = item.querySelector(".cardBox") || item.querySelector(".cardContent"); - parent.classList.add("withMultiSelect"), parent.appendChild(itemSelectionPanel); - var cssClass = "chkItemSelect"; - isChecked && !browser.firefox && (cssClass += " checkedInitial"); - var checkedAttribute = isChecked ? " checked" : ""; - itemSelectionPanel.innerHTML = '"; - itemSelectionPanel.querySelector(".chkItemSelect").addEventListener("change", onSelectionChange) + + itemSelectionPanel = document.createElement('div'); + itemSelectionPanel.classList.add('itemSelectionPanel'); + + var parent = item.querySelector('.cardBox') || item.querySelector('.cardContent'); + parent.classList.add('withMultiSelect'); + parent.appendChild(itemSelectionPanel); + + var cssClass = 'chkItemSelect'; + if (isChecked && !browser.firefox) { + // In firefox, the initial tap hold doesnt' get treated as a click + // In other browsers it does, so we need to make sure that initial click is ignored + cssClass += ' checkedInitial'; + } + var checkedAttribute = isChecked ? ' checked' : ''; + itemSelectionPanel.innerHTML = ''; + var chkItemSelect = itemSelectionPanel.querySelector('.chkItemSelect'); + chkItemSelect.addEventListener('change', onSelectionChange); } } function showSelectionCommands() { + var selectionCommandsPanel = currentSelectionCommandsPanel; + if (!selectionCommandsPanel) { - selectionCommandsPanel = document.createElement("div"), selectionCommandsPanel.classList.add("selectionCommandsPanel"), document.body.appendChild(selectionCommandsPanel), currentSelectionCommandsPanel = selectionCommandsPanel; - var html = ""; - html += '', html += '

'; - html += '', selectionCommandsPanel.innerHTML = html, selectionCommandsPanel.querySelector(".btnCloseSelectionPanel").addEventListener("click", hideSelections); - var btnSelectionPanelOptions = selectionCommandsPanel.querySelector(".btnSelectionPanelOptions"); - dom.addEventListener(btnSelectionPanelOptions, "click", showMenuForSelectedItems, { - passive: !0 - }) + + selectionCommandsPanel = document.createElement('div'); + selectionCommandsPanel.classList.add('selectionCommandsPanel'); + + document.body.appendChild(selectionCommandsPanel); + currentSelectionCommandsPanel = selectionCommandsPanel; + + var html = ''; + + html += ''; + html += '

'; + + var moreIcon = ''; + html += ''; + + selectionCommandsPanel.innerHTML = html; + + selectionCommandsPanel.querySelector('.btnCloseSelectionPanel').addEventListener('click', hideSelections); + + var btnSelectionPanelOptions = selectionCommandsPanel.querySelector('.btnSelectionPanelOptions'); + + dom.addEventListener(btnSelectionPanelOptions, 'click', showMenuForSelectedItems, { passive: true }); } } function alertText(options) { - return new Promise(function(resolve, reject) { - require(["alert"], function(alert) { - alert(options).then(resolve, resolve) - }) - }) + + return new Promise(function (resolve, reject) { + + require(['alert'], function (alert) { + alert(options).then(resolve, resolve); + }); + }); } function deleteItems(apiClient, itemIds) { - return new Promise(function(resolve, reject) { - var msg = globalize.translate("sharedcomponents#ConfirmDeleteItem"), - title = globalize.translate("sharedcomponents#HeaderDeleteItem"); - itemIds.length > 1 && (msg = globalize.translate("sharedcomponents#ConfirmDeleteItems"), title = globalize.translate("sharedcomponents#HeaderDeleteItems")), require(["confirm"], function(confirm) { - confirm(msg, title).then(function() { - var promises = itemIds.map(function(itemId) { - apiClient.deleteItem(itemId) + + return new Promise(function (resolve, reject) { + + var msg = globalize.translate('sharedcomponents#ConfirmDeleteItem'); + var title = globalize.translate('sharedcomponents#HeaderDeleteItem'); + + if (itemIds.length > 1) { + msg = globalize.translate('sharedcomponents#ConfirmDeleteItems'); + title = globalize.translate('sharedcomponents#HeaderDeleteItems'); + } + + require(['confirm'], function (confirm) { + + confirm(msg, title).then(function () { + var promises = itemIds.map(function (itemId) { + apiClient.deleteItem(itemId); }); - Promise.all(promises).then(resolve, function() { - alertText(globalize.translate("sharedcomponents#ErrorDeletingItem")).then(reject, reject) - }) - }, reject) - }) - }) + + Promise.all(promises).then(resolve, function () { + + alertText(globalize.translate('sharedcomponents#ErrorDeletingItem')).then(reject, reject); + }); + }, reject); + + }); + }); } function showMenuForSelectedItems(e) { + var apiClient = connectionManager.currentApiClient(); - apiClient.getCurrentUser().then(function(user) { + + apiClient.getCurrentUser().then(function (user) { + var menuItems = []; + menuItems.push({ - name: globalize.translate("sharedcomponents#AddToCollection"), - id: "addtocollection", - ironIcon: "add" - }), menuItems.push({ - name: globalize.translate("sharedcomponents#AddToPlaylist"), - id: "playlist", - ironIcon: "playlist-add" - }), user.Policy.EnableContentDeletion && menuItems.push({ - name: globalize.translate("sharedcomponents#Delete"), - id: "delete", - ironIcon: "delete" - }), user.Policy.EnableContentDownloading && appHost.supports("filedownload"), user.Policy.EnableContentDownloading && appHost.supports("sync") && menuItems.push({ - name: globalize.translate("sharedcomponents#Download"), - id: "synclocal" - }), menuItems.push({ - name: globalize.translate("sharedcomponents#GroupVersions"), - id: "groupvideos", - ironIcon: "call-merge" - }), menuItems.push({ - name: globalize.translate("sharedcomponents#MarkPlayed"), - id: "markplayed" - }), menuItems.push({ - name: globalize.translate("sharedcomponents#MarkUnplayed"), - id: "markunplayed" - }), menuItems.push({ - name: globalize.translate("sharedcomponents#RefreshMetadata"), - id: "refresh" - }), user.Policy.EnableContentDownloading && menuItems.push({ - name: globalize.translate("sharedcomponents#Sync"), - id: "sync" - }), require(["actionsheet"], function(actionsheet) { + name: globalize.translate('sharedcomponents#AddToCollection'), + id: 'addtocollection', + ironIcon: 'add' + }); + + menuItems.push({ + name: globalize.translate('sharedcomponents#AddToPlaylist'), + id: 'playlist', + ironIcon: 'playlist-add' + }); + + // TODO: Be more dynamic based on what is selected + if (user.Policy.EnableContentDeletion) { + menuItems.push({ + name: globalize.translate('sharedcomponents#Delete'), + id: 'delete', + ironIcon: 'delete' + }); + } + + if (user.Policy.EnableContentDownloading && appHost.supports('filedownload')) { + //items.push({ + // name: Globalize.translate('ButtonDownload'), + // id: 'download', + // ironIcon: 'file-download' + //}); + } + + if (user.Policy.EnableContentDownloading && appHost.supports('sync')) { + menuItems.push({ + name: globalize.translate('sharedcomponents#Download'), + id: 'synclocal' + }); + } + + menuItems.push({ + name: globalize.translate('sharedcomponents#GroupVersions'), + id: 'groupvideos', + ironIcon: 'call-merge' + }); + + menuItems.push({ + name: globalize.translate('sharedcomponents#MarkPlayed'), + id: 'markplayed' + }); + + menuItems.push({ + name: globalize.translate('sharedcomponents#MarkUnplayed'), + id: 'markunplayed' + }); + + menuItems.push({ + name: globalize.translate('sharedcomponents#RefreshMetadata'), + id: 'refresh' + }); + + if (user.Policy.EnableContentDownloading) { + menuItems.push({ + name: globalize.translate('sharedcomponents#Sync'), + id: 'sync' + }); + } + + require(['actionsheet'], function (actionsheet) { + actionsheet.show({ items: menuItems, positionTo: e.target, - callback: function(id) { - var items = selectedItems.slice(0), - serverId = apiClient.serverInfo().Id; + callback: function (id) { + + var items = selectedItems.slice(0); + var serverId = apiClient.serverInfo().Id; + switch (id) { - case "addtocollection": - require(["collectionEditor"], function(collectionEditor) { - (new collectionEditor).show({ + + case 'addtocollection': + require(['collectionEditor'], function (collectionEditor) { + + new collectionEditor().show({ items: items, serverId: serverId - }) - }), hideSelections(), dispatchNeedsRefresh(); + }); + }); + hideSelections(); + dispatchNeedsRefresh(); break; - case "playlist": - require(["playlistEditor"], function(playlistEditor) { - (new playlistEditor).show({ + case 'playlist': + require(['playlistEditor'], function (playlistEditor) { + new playlistEditor().show({ items: items, serverId: serverId - }) - }), hideSelections(), dispatchNeedsRefresh(); + }); + }); + hideSelections(); + dispatchNeedsRefresh(); break; - case "delete": - deleteItems(apiClient, items).then(dispatchNeedsRefresh), hideSelections(), dispatchNeedsRefresh(); + case 'delete': + deleteItems(apiClient, items).then(dispatchNeedsRefresh); + hideSelections(); + dispatchNeedsRefresh(); break; - case "groupvideos": + case 'groupvideos': combineVersions(apiClient, items); break; - case "markplayed": - items.forEach(function(itemId) { - apiClient.markPlayed(apiClient.getCurrentUserId(), itemId) - }), hideSelections(), dispatchNeedsRefresh(); + case 'markplayed': + items.forEach(function (itemId) { + apiClient.markPlayed(apiClient.getCurrentUserId(), itemId); + }); + hideSelections(); + dispatchNeedsRefresh(); break; - case "markunplayed": - items.forEach(function(itemId) { - apiClient.markUnplayed(apiClient.getCurrentUserId(), itemId) - }), hideSelections(), dispatchNeedsRefresh(); + case 'markunplayed': + items.forEach(function (itemId) { + apiClient.markUnplayed(apiClient.getCurrentUserId(), itemId); + }); + hideSelections(); + dispatchNeedsRefresh(); break; - case "refresh": - require(["refreshDialog"], function(refreshDialog) { + case 'refresh': + require(['refreshDialog'], function (refreshDialog) { new refreshDialog({ itemIds: items, serverId: serverId - }).show() - }), hideSelections(), dispatchNeedsRefresh(); + }).show(); + }); + hideSelections(); + dispatchNeedsRefresh(); break; - case "sync": - require(["syncDialog"], function(syncDialog) { + case 'sync': + require(['syncDialog'], function (syncDialog) { syncDialog.showMenu({ - items: items.map(function(i) { + items: items.map(function (i) { return { Id: i - } + }; }), serverId: serverId - }) - }), hideSelections(), dispatchNeedsRefresh(); + }); + }); + hideSelections(); + dispatchNeedsRefresh(); break; - case "synclocal": - require(["syncDialog"], function(syncDialog) { + case 'synclocal': + require(['syncDialog'], function (syncDialog) { syncDialog.showMenu({ - items: items.map(function(i) { + items: items.map(function (i) { return { Id: i - } + }; }), - isLocalSync: !0, + isLocalSync: true, serverId: serverId - }) - }), hideSelections(), dispatchNeedsRefresh() + }); + }); + hideSelections(); + dispatchNeedsRefresh(); + break; + default: + break; } } - }) - }) - }) + }); + + }); + }); } function dispatchNeedsRefresh() { + var elems = []; - [].forEach.call(selectedElements, function(i) { - var container = dom.parentWithAttribute(i, "is", "emby-itemscontainer"); - container && -1 === elems.indexOf(container) && elems.push(container) + + [].forEach.call(selectedElements, function (i) { + + var container = dom.parentWithAttribute(i, 'is', 'emby-itemscontainer'); + + if (container && elems.indexOf(container) === -1) { + elems.push(container); + } }); - for (var i = 0, length = elems.length; i < length; i++) elems[i].notifyRefreshNeeded(!0) + + for (var i = 0, length = elems.length; i < length; i++) { + elems[i].notifyRefreshNeeded(true); + } } function combineVersions(apiClient, selection) { - if (selection.length < 2) return void require(["alert"], function(alert) { - alert({ - text: globalize.translate("sharedcomponents#PleaseSelectTwoItems") - }) - }); - loading.show(), apiClient.ajax({ + + if (selection.length < 2) { + + require(['alert'], function (alert) { + alert({ + text: globalize.translate('sharedcomponents#PleaseSelectTwoItems') + }); + }); + return; + } + + loading.show(); + + apiClient.ajax({ + type: "POST", - url: apiClient.getUrl("Videos/MergeVersions", { - Ids: selection.join(",") - }) - }).then(function() { - loading.hide(), hideSelections(), dispatchNeedsRefresh() - }) + url: apiClient.getUrl("Videos/MergeVersions", { Ids: selection.join(',') }) + + }).then(function () { + + loading.hide(); + hideSelections(); + dispatchNeedsRefresh(); + }); } function showSelections(initialCard) { - require(["emby-checkbox"], function() { - for (var cards = document.querySelectorAll(".card"), i = 0, length = cards.length; i < length; i++) showSelection(cards[i], initialCard === cards[i]); - showSelectionCommands(), updateItemSelection(initialCard, !0) - }) + + require(['emby-checkbox'], function () { + var cards = document.querySelectorAll('.card'); + for (var i = 0, length = cards.length; i < length; i++) { + showSelection(cards[i], initialCard === cards[i]); + } + + showSelectionCommands(); + updateItemSelection(initialCard, true); + }); } function onContainerClick(e) { + var target = e.target; + if (selectedItems.length) { - var card = dom.parentWithClass(target, "card"); + + var card = dom.parentWithClass(target, 'card'); if (card) { - var itemSelectionPanel = card.querySelector(".itemSelectionPanel"); - if (itemSelectionPanel) return onItemSelectionPanelClick(e, itemSelectionPanel) + var itemSelectionPanel = card.querySelector('.itemSelectionPanel'); + if (itemSelectionPanel) { + return onItemSelectionPanelClick(e, itemSelectionPanel); + } } - return e.preventDefault(), e.stopPropagation(), !1 + + e.preventDefault(); + e.stopPropagation(); + return false; } } - var currentSelectionCommandsPanel, selectedItems = [], - selectedElements = []; - return document.addEventListener("viewbeforehide", hideSelections), - function(options) { - function onTapHold(e) { - var card = dom.parentWithClass(e.target, "card"); - return card && showSelections(card), e.preventDefault(), e.stopPropagation && e.stopPropagation(), !1 + + document.addEventListener('viewbeforehide', hideSelections); + + return function (options) { + + var self = this; + + var container = options.container; + + function onTapHold(e) { + + var card = dom.parentWithClass(e.target, 'card'); + + if (card) { + + showSelections(card); } - function getTouches(e) { - return e.changedTouches || e.targetTouches || e.touches + e.preventDefault(); + // It won't have this if it's a hammer event + if (e.stopPropagation) { + e.stopPropagation(); } + return false; + } - function onTouchStart(e) { - var touch = getTouches(e)[0]; - if (touchTarget = null, touchStartX = 0, touchStartY = 0, touch) { - touchStartX = touch.clientX, touchStartY = touch.clientY; - var element = touch.target; - if (element) { - var card = dom.parentWithClass(element, "card"); - card && (touchStartTimeout && (clearTimeout(touchStartTimeout), touchStartTimeout = null), touchTarget = card, touchStartTimeout = setTimeout(onTouchStartTimerFired, 550)) + function getTouches(e) { + + return e.changedTouches || e.targetTouches || e.touches; + } + + var touchTarget; + var touchStartTimeout; + var touchStartX; + var touchStartY; + function onTouchStart(e) { + + var touch = getTouches(e)[0]; + touchTarget = null; + touchStartX = 0; + touchStartY = 0; + + if (touch) { + touchStartX = touch.clientX; + touchStartY = touch.clientY; + var element = touch.target; + + if (element) { + var card = dom.parentWithClass(element, 'card'); + + if (card) { + + if (touchStartTimeout) { + clearTimeout(touchStartTimeout); + touchStartTimeout = null; + } + + touchTarget = card; + touchStartTimeout = setTimeout(onTouchStartTimerFired, 550); } } } + } - function onTouchMove(e) { - if (touchTarget) { - var deltaX, deltaY, touch = getTouches(e)[0]; - if (touch) { - var touchEndX = touch.clientX || 0, - touchEndY = touch.clientY || 0; - deltaX = Math.abs(touchEndX - (touchStartX || 0)), deltaY = Math.abs(touchEndY - (touchStartY || 0)) - } else deltaX = 100, deltaY = 100; - (deltaX >= 5 || deltaY >= 5) && onMouseOut(e) + function onTouchMove(e) { + + if (touchTarget) { + var touch = getTouches(e)[0]; + var deltaX; + var deltaY; + + if (touch) { + var touchEndX = touch.clientX || 0; + var touchEndY = touch.clientY || 0; + deltaX = Math.abs(touchEndX - (touchStartX || 0)); + deltaY = Math.abs(touchEndY - (touchStartY || 0)); + } else { + deltaX = 100; + deltaY = 100; } - } - - function onTouchEnd(e) { - onMouseOut(e) - } - - function onMouseDown(e) { - touchStartTimeout && (clearTimeout(touchStartTimeout), touchStartTimeout = null), touchTarget = e.target, touchStartTimeout = setTimeout(onTouchStartTimerFired, 550) - } - - function onMouseOut(e) { - touchStartTimeout && (clearTimeout(touchStartTimeout), touchStartTimeout = null), touchTarget = null - } - - function onTouchStartTimerFired() { - if (touchTarget) { - var card = dom.parentWithClass(touchTarget, "card"); - touchTarget = null, card && showSelections(card) + if (deltaX >= 5 || deltaY >= 5) { + onMouseOut(e); } } - var touchTarget, touchStartTimeout, touchStartX, touchStartY, self = this, - container = options.container; - ! function(element) { - browser.touch && !browser.safari ? element.addEventListener("contextmenu", onTapHold) : (dom.addEventListener(element, "touchstart", onTouchStart, { - passive: !0 - }), dom.addEventListener(element, "touchmove", onTouchMove, { - passive: !0 - }), dom.addEventListener(element, "touchend", onTouchEnd, { - passive: !0 - }), dom.addEventListener(element, "touchcancel", onTouchEnd, { - passive: !0 - }), dom.addEventListener(element, "mousedown", onMouseDown, { - passive: !0 - }), dom.addEventListener(element, "mouseleave", onMouseOut, { - passive: !0 - }), dom.addEventListener(element, "mouseup", onMouseOut, { - passive: !0 - })) - }(container), !1 !== options.bindOnClick && container.addEventListener("click", onContainerClick), self.onContainerClick = onContainerClick, self.destroy = function() { - container.removeEventListener("click", onContainerClick), container.removeEventListener("contextmenu", onTapHold); - var element = container; - dom.removeEventListener(element, "touchstart", onTouchStart, { - passive: !0 - }), dom.removeEventListener(element, "touchmove", onTouchMove, { - passive: !0 - }), dom.removeEventListener(element, "touchend", onTouchEnd, { - passive: !0 - }), dom.removeEventListener(element, "mousedown", onMouseDown, { - passive: !0 - }), dom.removeEventListener(element, "mouseleave", onMouseOut, { - passive: !0 - }), dom.removeEventListener(element, "mouseup", onMouseOut, { - passive: !0 - }) - } } + + function onTouchEnd(e) { + + onMouseOut(e); + } + + function onMouseDown(e) { + + if (touchStartTimeout) { + clearTimeout(touchStartTimeout); + touchStartTimeout = null; + } + + touchTarget = e.target; + touchStartTimeout = setTimeout(onTouchStartTimerFired, 550); + } + + function onMouseOut(e) { + + if (touchStartTimeout) { + clearTimeout(touchStartTimeout); + touchStartTimeout = null; + } + touchTarget = null; + } + + function onTouchStartTimerFired() { + + if (!touchTarget) { + return; + } + + var card = dom.parentWithClass(touchTarget, 'card'); + touchTarget = null; + + if (card) { + + showSelections(card); + } + } + + function initTapHold(element) { + + // mobile safari doesn't allow contextmenu override + if (browser.touch && !browser.safari) { + element.addEventListener('contextmenu', onTapHold); + } else { + dom.addEventListener(element, 'touchstart', onTouchStart, { + passive: true + }); + dom.addEventListener(element, 'touchmove', onTouchMove, { + passive: true + }); + dom.addEventListener(element, 'touchend', onTouchEnd, { + passive: true + }); + dom.addEventListener(element, 'touchcancel', onTouchEnd, { + passive: true + }); + dom.addEventListener(element, 'mousedown', onMouseDown, { + passive: true + }); + dom.addEventListener(element, 'mouseleave', onMouseOut, { + passive: true + }); + dom.addEventListener(element, 'mouseup', onMouseOut, { + passive: true + }); + } + } + + initTapHold(container); + + if (options.bindOnClick !== false) { + container.addEventListener('click', onContainerClick); + } + + self.onContainerClick = onContainerClick; + + self.destroy = function () { + + container.removeEventListener('click', onContainerClick); + container.removeEventListener('contextmenu', onTapHold); + + var element = container; + + dom.removeEventListener(element, 'touchstart', onTouchStart, { + passive: true + }); + dom.removeEventListener(element, 'touchmove', onTouchMove, { + passive: true + }); + dom.removeEventListener(element, 'touchend', onTouchEnd, { + passive: true + }); + // this fires in safari due to magnifying class + //dom.removeEventListener(element, 'touchcancel', onTouchEnd, { + // passive: true + //}); + dom.removeEventListener(element, 'mousedown', onMouseDown, { + passive: true + }); + dom.removeEventListener(element, 'mouseleave', onMouseOut, { + passive: true + }); + dom.removeEventListener(element, 'mouseup', onMouseOut, { + passive: true + }); + }; + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/native-promise-only/lib/npo.src.js b/src/bower_components/emby-webcomponents/native-promise-only/lib/npo.src.js index 888d602450..1c8cb07867 100644 --- a/src/bower_components/emby-webcomponents/native-promise-only/lib/npo.src.js +++ b/src/bower_components/emby-webcomponents/native-promise-only/lib/npo.src.js @@ -1,166 +1,373 @@ -! function(name, context, definition) { - context[name] = definition(), "undefined" != typeof module && module.exports ? module.exports = context[name] : "function" == typeof define && define.amd && define(function() { - return context[name] - }) -}("Promise", "undefined" != typeof global ? global : this, function() { - "use strict"; +/*! Native Promise Only + v0.8.0-a (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ - function schedule(fn, self) { - scheduling_queue.add(fn, self), cycle || (cycle = timer(scheduling_queue.drain)) - } +(function UMD(name,context,definition){ + // special form of UMD for polyfilling across evironments + 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(){ + /*jshint validthis:true */ + "use strict"; - function isThenable(o) { - var _then, o_type = typeof o; - return null == o || "object" != o_type && "function" != o_type || (_then = o.then), "function" == typeof _then && _then - } + var builtInProp, cycle, scheduling_queue, + ToString = Object.prototype.toString, + timer = (typeof setImmediate != "undefined") ? + function timer(fn) { return setImmediate(fn); } : + setTimeout + ; - function notify() { - for (var i = 0; i < this.chain.length; i++) notifyIsolated(this, 1 === this.state ? this.chain[i].success : this.chain[i].failure, this.chain[i]); - this.chain.length = 0 - } + // dammit, IE8. + try { + Object.defineProperty({},"x",{}); + builtInProp = function builtInProp(obj,name,val,config) { + return Object.defineProperty(obj,name,{ + value: val, + writable: true, + configurable: config !== false + }); + }; + } + catch (err) { + builtInProp = function builtInProp(obj,name,val) { + obj[name] = val; + return obj; + }; + } - function notifyIsolated(self, cb, chain) { - var ret, _then; - try { - !1 === cb ? chain.reject(self.msg) : (ret = !0 === cb ? self.msg : cb.call(void 0, self.msg), ret === chain.promise ? chain.reject(TypeError("Promise-chain cycle")) : (_then = isThenable(ret)) ? _then.call(ret, chain.resolve, chain.reject) : chain.resolve(ret)) - } catch (err) { - chain.reject(err) - } - } + // Note: using a queue instead of array for efficiency + scheduling_queue = (function Queue() { + var first, last, item; - function resolve(msg) { - var _then, self = this; - if (!self.triggered) { - self.triggered = !0, self.def && (self = self.def); - try { - (_then = isThenable(msg)) ? schedule(function() { - var def_wrapper = new MakeDefWrapper(self); - try { - _then.call(msg, function() { - resolve.apply(def_wrapper, arguments) - }, function() { - reject.apply(def_wrapper, arguments) - }) - } catch (err) { - reject.call(def_wrapper, err) - } - }): (self.msg = msg, self.state = 1, self.chain.length > 0 && schedule(notify, self)) - } catch (err) { - reject.call(new MakeDefWrapper(self), err) - } - } - } + function Item(fn,self) { + this.fn = fn; + this.self = self; + this.next = void 0; + } - function reject(msg) { - var self = this; - self.triggered || (self.triggered = !0, self.def && (self = self.def), self.msg = msg, self.state = 2, self.chain.length > 0 && schedule(notify, self)) - } + return { + add: function add(fn,self) { + item = new Item(fn,self); + if (last) { + last.next = item; + } + else { + first = item; + } + last = item; + item = void 0; + }, + drain: function drain() { + var f = first; + first = last = cycle = void 0; - function iteratePromises(Constructor, arr, resolver, rejecter) { - for (var idx = 0; idx < arr.length; idx++) ! function(idx) { - Constructor.resolve(arr[idx]).then(function(msg) { - resolver(idx, msg) - }, rejecter) - }(idx) - } + while (f) { + f.fn.call(f.self); + f = f.next; + } + } + }; + })(); - function MakeDefWrapper(self) { - this.def = self, this.triggered = !1 - } + function schedule(fn,self) { + scheduling_queue.add(fn,self); + if (!cycle) { + cycle = timer(scheduling_queue.drain); + } + } - function MakeDef(self) { - this.promise = self, this.state = 0, this.triggered = !1, this.chain = [], this.msg = void 0 - } + // promise duck typing + function isThenable(o) { + var _then, o_type = typeof o; - function Promise(executor) { - if ("function" != typeof executor) throw TypeError("Not a function"); - if (0 !== this.__NPO__) throw TypeError("Not a promise"); - this.__NPO__ = 1; - var def = new MakeDef(this); - this.then = function(success, failure) { - var o = { - success: "function" != typeof success || success, - failure: "function" == typeof failure && failure - }; - return o.promise = new this.constructor(function(resolve, reject) { - if ("function" != typeof resolve || "function" != typeof reject) throw TypeError("Not a function"); - o.resolve = resolve, o.reject = reject - }), def.chain.push(o), 0 !== def.state && schedule(notify, def), o.promise - }, this.catch = function(failure) { - return this.then(void 0, failure) - }; - try { - executor.call(void 0, function(msg) { - resolve.call(def, msg) - }, function(msg) { - reject.call(def, msg) - }) - } catch (err) { - reject.call(def, err) - } - } - var builtInProp, cycle, scheduling_queue, ToString = Object.prototype.toString, - timer = "undefined" != typeof setImmediate ? function(fn) { - return setImmediate(fn) - } : setTimeout; - try { - Object.defineProperty({}, "x", {}), builtInProp = function(obj, name, val, config) { - return Object.defineProperty(obj, name, { - value: val, - writable: !0, - configurable: !1 !== config - }) - } - } catch (err) { - builtInProp = function(obj, name, val) { - return obj[name] = val, obj - } - } - scheduling_queue = function() { - function Item(fn, self) { - this.fn = fn, this.self = self, this.next = void 0 - } - var first, last, item; - return { - add: function(fn, self) { - item = new Item(fn, self), last ? last.next = item : first = item, last = item, item = void 0 - }, - drain: function() { - var f = first; - for (first = last = cycle = void 0; f;) f.fn.call(f.self), f = f.next - } - } - }(); - var PromisePrototype = builtInProp({}, "constructor", Promise, !1); - return Promise.prototype = PromisePrototype, builtInProp(PromisePrototype, "__NPO__", 0, !1), builtInProp(Promise, "resolve", function(msg) { - var Constructor = this; - return msg && "object" == typeof msg && 1 === msg.__NPO__ ? msg : new Constructor(function(resolve, reject) { - if ("function" != typeof resolve || "function" != typeof reject) throw TypeError("Not a function"); - resolve(msg) - }) - }), builtInProp(Promise, "reject", function(msg) { - return new this(function(resolve, reject) { - if ("function" != typeof resolve || "function" != typeof reject) throw TypeError("Not a function"); - reject(msg) - }) - }), builtInProp(Promise, "all", function(arr) { - var Constructor = this; - return "[object Array]" != ToString.call(arr) ? Constructor.reject(TypeError("Not an array")) : 0 === arr.length ? Constructor.resolve([]) : new Constructor(function(resolve, reject) { - if ("function" != typeof resolve || "function" != typeof reject) throw TypeError("Not a function"); - var len = arr.length, - msgs = Array(len), - count = 0; - iteratePromises(Constructor, arr, function(idx, msg) { - msgs[idx] = msg, ++count === len && resolve(msgs) - }, reject) - }) - }), builtInProp(Promise, "race", function(arr) { - var Constructor = this; - return "[object Array]" != ToString.call(arr) ? Constructor.reject(TypeError("Not an array")) : new Constructor(function(resolve, reject) { - if ("function" != typeof resolve || "function" != typeof reject) throw TypeError("Not a function"); - iteratePromises(Constructor, arr, function(idx, msg) { - resolve(msg) - }, reject) - }) - }), Promise -}); \ No newline at end of file + if (o != null && + ( + o_type == "object" || o_type == "function" + ) + ) { + _then = o.then; + } + return typeof _then == "function" ? _then : false; + } + + function notify() { + for (var i=0; i 0) { + schedule(notify,self); + } + } + } + catch (err) { + reject.call(new MakeDefWrapper(self),err); + } + } + + function reject(msg) { + var self = this; + + // already triggered? + if (self.triggered) { return; } + + self.triggered = true; + + // unwrap + if (self.def) { + self = self.def; + } + + self.msg = msg; + self.state = 2; + if (self.chain.length > 0) { + schedule(notify,self); + } + } + + function iteratePromises(Constructor,arr,resolver,rejecter) { + for (var idx=0; idxp#xiXeg@(!wYuVi2!l z83+WTVn~8;l{O?qE)Eee2`wg<8YvnC0^E~3@7H%e-w$^^&)(14zw_T~{rCEI@;u!g zm3C_Ggg_ul&Q52%A&@Q2vb9|fB#=E@Gr?W{lD(Tf1VSl>N<$SO5IKma>v;!rb92qa zOwFXs{YhEgP3Nxjrf!Z*XOB+jj?NU0&z1@19()l$6pH^Y`ucowo;mNY%kxw7$;BX=xC5|H`u4m&yGFXBymuA*Hd+RnzN8FTt%QatU3U1B^9uuG1o z1+{`l_bPC+s{)VkATZMj0yAZDVmvZ^kU^`YHv#Y$F>i^iqYMsPn7|i{aJ3`TBHV)! zFv}NDiEydn84)f@JSV~hh`)+(E^iXzk=k53tunu!k8y98fcHZ@5CjsnfynaVa@oSD zIZ#%HPl%_T=%&*!Wy`Z|x+>u{c(Cuz10ZNM<7435-vBt_3I;)7S-d2&g!{pJFAKqz z$SzQ}>nBhVMW zE$r$6y;g^V3bRE9jkkR-A0uvl0Kk*a`ydF`&&foVwihUqkU-gWA5fM)4a#(Og4L{x z064YG1wr7ReL-Z!JRV>R#Vh3aP9XFEcHaK@scz8A`ABRe^wx>BW+=7A6Kna1^%pDLu7hA^BdKhkjz$#Eu zZf#G^%~i1(u7IV7eb&K{jR-SLAst5}|3w|QB&v7=-9_r}oZnAStdQo_T*Mn-}g@r!p<6HjBg@hzV_VqMr`AJJtM`Ts+ zjqI5O67ez2LkOXpZ1i0E_WfA*Ze&)}zKn_ZMLIzc2|Hz;K;wLecb8b*#y(1y?tipz zkOuP@*UL)hd_fOVVIE^gaJC!)dawyb$k3ovt(gRuetHGlmjSB@x*SKE@x!0fz3JT` zz13heIK`}O?M8dC6ZU`uW<2B!tuJ^*-=Xel?u=H^!DY2p z4y8ns3|M9H=5m79RVKnE>#Y%Tx!mP091BO61GTiylJa%Hm7RufC_^f>kFHDk4> zJh4WcK<$Fau?JXHtaX2&Hu30Ke%7y{#clJd0e?!GN=?c8cr zAdHGLi96CroS6A_n5^cjc4u8hwS_|o(k35Jo6&u;JYg&$z4yt+u7!OA5{>SG91w7I;%U;7I5qXwg*$GUCdVOPu2b< zFk<41ys=&3Kt2BWQY^4dqT@8x=|5YMgF-b*oLm}CNA$xgD{fJ`)#w~b-wuySkrZN3FJkl}AirB?Z?G_>4}==)o|a-!sshj21;!bNK(EPs4^{N8^Gl zMM~{vD?`Wad;To3Cxo+Sg?d6p_YPS&FaAkOL;8(t{w#sIWxw?0&k}n=Ke#&oAI&jC zJ!?^}xYi!)y8n%f@r`i3}Bu9QzV!K1v|_TGRdHsM^L=ZJEcd zLl*X3oAln6P^+_BNVm_ekf5@<2OF=vE^RaJkYTy@F6N5$fAAU8n5R$MR9P~tAn58@ zHJX&E!%eT=AB}al5P{SDWeDN)nN{b9P&23r8CSj5APM36RUXPJl1q~wb?gWmzFhe{ zv#k4E+JYUUOJK93*Cs%8<&OVxIRnFxNs4!dy%JG0=DNkz)?3_=jqNwC3@D~3GS}G_ zvlY4VEQ-Xmr%m$faq~Fbaf!~sHEILpBK!lqYvOd;X1tCC^jw7CTR^nksnuhDM0BTB z2Iuz|vo;^L*7;=`{njz-xVI%#UhC7C=1w!I+1{)D@3VZG^G~>DICWY(GzM#vt9NmA zJr^y*>wNQ!YTmChI4xRgT+T#5e&eS5$$^$l4VI4}D#|nD(GvvqA~hA`u|sXv>$?uI z?)gol+P`JbF-QLKkZlp`rto{C53|9Lmfv|k)@Nlq#fxuEeMP{lVEimyqP-W11}8&J z4mk)fQ|yP?G4Id;QA{rZuxZ4gnfST5IU`efSEffVwFWvMvv@D&MQ=h5IVcF7aK*L3 z;mVdDOM~%8l8@XVz|_6Vg7Ah{4d2pCh8%s9ko1z0g=MC@=!x7i0ku0~-n2$JvNz02gR06S) z=S+9=6rD!ed=nOdKIVnt ztcFQsI@Lf(2Hp)0G;=4`*(P@BUWJSc7-l^X=kHR$2tAq{2L1GL90+b{qbXdkiKQ|q z_qQc;Z?g9^a}U>{`}mevYLxiReijEu)gB_>W6ZrzP2|NGNJtX^gA$^YY<*M7sF|x@ zcfXIXjO~sVCuy7$;iy}Nekoxny?bzt7o#faodDV!FDoZ&-ElK-=6cp?_VKrc4PF*o z!dP86DkNH~hkvROfF(oUw|enRc0m=#RiXdr(6@Sj$`l7tZq)0wfvH>#)krnf;cYeh z?rHNn2RoaY5(4ewwa+)Iv;$|dlzv*fWED&wa|{fvxhiejn3E5 zn!klEge42Q>tOcc4wVYXJzkEk*^V+DE8i+1clL%C%=E&8EomFotk;7e zN0vC6&O2YZ8NM%#8KCz$%foMXcsw z{oh;9wOB64;rs4A_uO;$*?V93o7aj2kEkDkKp+BTB?S!-2weB@gM$TpBHDjc3H*iO z`a)R?2l(TQV;%wg8`oJ$&lULo>BA4W^v>G?_>ju&rLLQ%lck%d$wv#2r>7^cjia5b znTfLnuhU1X)IA6_2*dzVR*=*3O4~{I%+#8!zHdPd@(7Jt??`{<@21q^&VOvC9K)6? zrS_ON>+RQ%HfNu{;NVcmmcQL0c>YS$NKH-N28;oR-%Nb(Ogf9R-XW;-9KO1B*-w`g zv^p0bAKn>xTDFm}za!~tSz0}9grfb_vkp)9Q7m4R#CJvu90|N|2Kn%n(SZ04o`LU8 zvzEi6zkx%c0sAHEccm3lXI^pG?;6nQp&DMsoeg(%1iQ0hHQWo+L;Y5O;bgA{3F;7< zVVny%gFs!}gZ$+f4YT@phxj+4ve`X6bVmt`AJz^ho-DO`Lr5t;&(6&F%-7iALcRrM z`ZT(oS;p$d&3mK~gbmj1Rr}SbL-U~9e7C6(1gxD#EJm@_kH^k~c`aP-f;%%Kl#@*L z@rE*~s>D1SEczRPT#siDuk>ApWk7O|rVPfFJOpvI)+RVj3kBbcm@ecvXf#It8qJZ@ z&q*4WZceB1Z#+m7&Ulv&42St)IN}R3wnIW#_m5f;vFX3wn40_eTWdt9T5F7AmC=yg z?j-Wtv2!d9trtl8M*Lm}m#uY@6Wq^~x_|?5J#d-Us%uGE62EWr`1_SQkli$-^{fNo z2$mc%Ldt7mCz7n1GfXKEAA0B@OZ>1buw8|vCdXAT zFcz@_5tZ6@y#D~Y`-ocm(GuRH8GgY+1~oi#9{6RJd|1_6_m|NHoG!>13VRJ_C9UWt zVAvril@bovNnw1I2ZP{t(1<}74_ou!eIS7Q6BsA$In?~u=W|n=#f*V*v z(ve`R66%gtCO5-B1`+Y&bWnp`vJ6^%~K5px9QItx0Y4#v>wd?AdJdF!05+S z)I4Qfi%|sHcRM^U+M2VbXS86yW>cv+L7u}jwR_yhnh?ZX$8?)F>43adi8$V%=f`39 zJy_n?x(teyIik$b)&lu>YUJ0Tw@()M|Hyeka63m5g5)EUuvXgsj(#6M;TLMs%yYd0J7enF6k`F+bhj;Z~2I=%L+&@$Wy zQXLF@RiWH|BBhkfgi1{X%#eZn`!>}A3_~LPg-9?RrZZ}nWHg84Ie_J02@6*&k>JO8 zjy}o($($QND>{kpN3*}0rsS27!J~@F`*o>Y)%?Ey-&?uvktH{num%N#G_**xPDfr*fBvB6F$6)~31pD^ z@B0oSN2~+P$0dw^YYg{AZAetKMz9KNxMdeO554nlY-;^B-n(_J7f?TBGc8e!fj5=x z1~@dhCPjrkQA5Xdm1}n>OfY&@J z))`f#S-1Rg&KoYacQlWEPe>0XSdmXaq+}KY#XuY<0AGIH@{_VDTzf>|B+t-{%Sta0 zxkUJQ1zul_IxF|$ipev5CpRiWRpOWz69p%4ECkHFjY( z?23-_4W}d@q*n?&fcR($OZs1|@)-M;SgD>SU@C>ulF7N<4s?l>ch+&Y>JsJMn4HH9 zy^VxH$RD=vZnD37zO1n1QBl|V{LH0ydIIc8aeR#h4VD)M2nmVQNGO#y2VNC z9>R$4BrQf*n8HQybzj0+H5?*^9tnF8O0@Ufd`^~{3-%Kq;aq2f!DKWU|^BsA|FrX7!R>Pw?XZ4Q%!s7GN^I( zL|qi_uQd9gPBurJG4g8*w$qb9XPJGLx z6bomqpI=wPfUB40>4hL%m?9Q}BJ_!@i6W#knzz1xJMij%h)BhM5ur7f65O9b4!Q3R zagcN}m9s!4!#YW;5%Y8UeJ4l5WWLym$=}6c_k=I#6O6f*YYr}jFg5t+pI`t(xh}e2qDL+Y%9U}a8;uc@1CxBH zUKK}o*ZNL>LFgyJS(J@(+8MfQB@P97DGpSoG%8iUHLIiEXAhPH5DqlWo>NyMydj4V z`@3RH#PpO(?IyD+alrA6E#+G$iAn;wyJRW&Rn3zpDj1zuy!29${)vQCKS-spHfaQ% zB(4;JF$X@p@nAH$5IaYp2^=D=0bOQw$!>?U&U&c9SPKut{(>C{WPf@(apQnrFGGq^Z&*rVOpR1>IGInU%|Fp?5y0} zxM>6}&9a*n>7g#bX5$neTDaB*Wh4?s?)^~a${cUcBXJf zk?x`Q&`A+|{r+b3DB|4`H3Fi`D=}!nL!Bmtd6qVk8`Gprm8!Mf(95FrMldl)n5IysGx`PUl9Lf_n@aL-?k^-!ypcz4p@MVhLf6&qiiTh zNQFLd6~8@EI2uh$2AmjRPe&1IKig48%DBP2zNjhaq?J|;$T;L4# zDTgTB=3u6&qoNby%OWGyw$dK&wJsox7fVeW@kGyvyOkTY>b_}m%Anf z@dplmo##5^hNY$!U|T5=!!}O)!G+xu+G`pw$jdbV#ah$f?QJ792v+wgtMEWWE4hTw zIfA*XEXQLxZG^5yf)TV5N9tJNtATnwI!PYl?c3VorHrw%-2+sKi|^7FTcbYfduBZ61+oY0f?iLoYG zkNh69NMMI#iCx6lv>C8m^Ih`}lvs%^V zb3O|l7x7gr`FFT^$fyz{IPiXomelzI9~}vLOrG-CG2H%5RpW9_EMgnNg1 z9TG@X{j_S5GPDbSdV26g2y4K0G`E*u;ty<1ftX9`oxX8krP7irMaqPK;xnnwW+Z4m z`?bq=DU4sYZg7lK`v-bgPal2c0E0M`HqlKkkEf0d4TnjND6@iAd_f4>5r!@fl#m-Ru|A# zb&B-%TRFXAguHx`ej)^CeIfO((cCWKCl?+cBgW@ck=R)Pk@Ora`mMZQ4|C0T}*NlxQdHRZ~@CzzKLke61X9Z9Pgay{9fxcXj40KN* z03T5vET!I-f-l~*dVD1}qoHu6Hz$~5LK;j2dkCSw2{(X3<}3bpBqWpuyhrJYQ9NoE z*!}d`Y>@DDLU0N1h{J}a+7hSTnLO|@gNSp<4`n36hht2+bOmyHw)O%ZIMdpdt;lX?_?|N?F02&lTV;$bl`yo zP|)6x8cs*}^KJLJxe>5ZqY8$}9QOs3%0o!AVf8(YVQiH>k59&U6DZ@2&LG}zYmo>R zq1m5$Axqc=YX2g@&x@xE>qDA19`J_?g3ei)v>)*th>#NYXUX?aq+F$j4%CM=4p7y~N?n+Mk~e@-JOu zX3=8u@BqlAHy2jANHvtaj6PH7lj@(|>3EhqRXAJ$!dpKRMf6JL>^Vv>&_&jr0$|5sL{#bJ7MKKG$9XB&!O5i8bYNsD-T+`N;zLseYsX3du|01LICH4%XG%It)AESABjeY+d)4Vv! zj|fTzU5SStJa#O++b`a^Wpf~VSK+oN@ylD$;E{1ymp+U%I-|`S1d53^xO701N@-Mo z+U}Z)eAji$)_9h@#cAb~3U7ZKzfXAvG5s^=GU5xt5jYQREmLZ7z2Y#q=QcgF{E0nl zwJhl4n(>l?UOqQKM-oliV>K;Xv_td!f?I`%-cGNQCdhGQG55S-Q9l0vxA)k3oR=`h zpb|gS=eyu_5l4{o)~@2c_r1OFF-=022C=MO{ zGwp9=aq)A})bv$l0cnLTIqYKxkjJjS1Ih-)_b94M%DPa(T-X|~!?e^jB9T)S>t5?r zr0e6{(YOG}awNITL^${~Ss_XUq``wbRP>cl=Fl&{LA#cpC66z`nTX7Uj#$fBZVh zo;c`ZHe%M|w|a}dJgxjKGOAQ^Z*jm;{7fHIvbC3Tw(mZq>)yxrGvB(eebEw@v3+aO zvh{Bpk+TYnw*M&cT}Sd*V&jl`&0n|suDVl(6o*)IpIBIW>hJg`MD^6~I*Z__ZoW+q zEVOIEQIzQ8Vi1&XaF!WqyOU8W+*fK~pD@Q-!W&R)DyWJFWc~2oamZQOx`omNg|Z=~U-IqsAM$CpSa5Kx?Kb}PVG6o3h;Sts*F*HKfX}& zC(2{8lF+lT`2#hjFUCeHCoC=`qivFEK(XkCmh2WyeA$n-QdE*?(ecbOhh1z$JqBbf z8SzT(y^vVx0rGvl<=WMVz-o9e@)#}>vfbzavRfY z8%rj*klEksY@6=;=4(nZk(wXMjB$P{rTWG>6R>g_o)vkvJ6JKLDCoQYKzR$+W+A@0 z6B*m>yxD-RFfk94*}E_#y}M_rIDT2L47jQJ;DZNUxgX7ks82mBy^wYK&fp|vj<>$} zHbaG%45?339-E5x)(DOTK#hb>thVX3pX%^J{@FY_WCiV`_K7&5+$3vt+O{vWpi(}S zQv*%`|CXOhOAcrGAgFu7IZz=rZ|%Yu@O83V3;M!7=JcWSvnS>cj~D%YDIZ-f&BGuc zLQ)(R2Khw&Z@UlG+^QynHHsfW09$xy`l5cLGhvm8Nktma;5TL1Sc|!B4F;9A#(Ul1 zmk@eoox&|cRyCBOQx}FfQ3zV68e7xchFN9r3qzH~4HbGqD< zwKQE)2b8n_`#?45+!yLv-YXF|w*}in3IugGkTWZbqF08PE93R^_EKhaS8b(L=c&>7 zk&)-mXw8#@qu6+;Dip>VQ<#tk-+Nl!UZ3mCuYc8Da?%JjGljnzH5y@D7;4oSMxM-4 zWIKA>0;o$(Y~WQ1H6>^SWIec8LIX)S4|l`C?e=R?W)S^j`6J1d9u%@t$o`x@@fBMA z$KMTo81LWgU910deEz;PGX^;HgO*T?)kL}yJ_jwU%G~}~Nyge~by0iFccVmAL>2Fsg2uPR|9Vu%V*dd_&m zdtW#!4Nbw;pj*m|x1RCcEz(Nq1FfY;BJYdd{;TeS)2Kw^s@ql*T;)wLFG%dgE#o?g z?G^Yn1*tON=Q4DrgK}aXxg1puNv-eTss#U)=& z3o_S*K+nlf^|}$dq+K2&9GjWC(4{3;pI?3@FP}&W0~9N+x%a@fE0|WN&TyYf2dWpS z)yrR=6Xn?+2&MDvDbpdBdd;$RDZjjeAAs3fxMu;jJhU-G9wlJ9F>OhpGjxkveW*EP ziE{L^#c*07?Uv6gou`Wy51o%Xj?UgB(6)KtS0&D?1;=aIm-%VC5|7ok z&e+;v*aN7f2F~g|$J+;u^hlz|%$(QP|KO-y=wnL&Jnxmf{53?0-t<@dnGIM^D>&<= zezDHYEgO|}dX;(abMo*B%xP{hm^$T(nwy`&6e{D>(6`szed)-)tNckULRibPTG5NAATrE(lh0*2B9r?$sPIUHBDVY&^Ij+E z&l*|i-1MjOM>slZ-d)}3JFt}kOJD(T96F}YEFU=uN=Yx{Ovvg5=JHIhKSefAk8-(( zPtjC9p_PgsJ67B`zFN~ulJRL+Q-cziP!S(!G5_BV z*$ON~zK22x_eq)64)%%Bo7?691esJF5|1!k&EVq#g;$P&z+cg)%qk8TWq1rJ!d=G< z+>nKjy9qp@f~$9TWX+mx=^Z_ggFHb)^T#m=>er+(t`)@Yppno z^gNBIlq&`P<%dU`Za5jz#GZPAdKrVwcE_EhJ`Oue3ESU`w{r8a4zNnPw|;p`mOJ}g zPAmV)<7U8j9?E&yVfzoh@Xhk$mvN-b|a5W39r`sbDr;`86k>vNZiBWTv%BZ=EQ zcoBl-Ec0KsF&W!mnswXTNADa?;4igK@(~aah=MPyS3QtcMHvmV-rbXLDP&s*=yvCu zT_3PXWTn)L2phazF6q9US2i^DS9qX% zgDPlxor#PO8I@Syn(x->qv3(sJO5{0!9A0Q=_+e0S$!k43Y_+!QJJGfG1gBErYn)- zQI@Z%)2(7VwVao*88yNeWL#Ic4kl>*v2=nVV^<1-t#~i5PY^}zbp>;iMijC_Z8WuO z^?SM5AJC5L0SrG~0ZK+x@$lmHYNQ-^XMm_a(CB1)q3Z-U-CN#sfoZks7N-Qi7$Zv< zp96<<{e)59>0U~mS16sXcp<%_qeG6KO?V(w6e59oo^9~|p_kDc91 zA(IiJ&cd(ednd8^XSNXDHRq|^`x0jidZ;px^;$PKpoUi?i8m=)u9VcN}WDv7L&vd%u~^52UO$h$5Lhhf{L(p zG0L`Te!ZqmAsc;2mPqI=m$S)<_^zP^THN#q$-0Cf0OI8OJG{yQp6z)WKhpL1$WY>wjz-SrV1LjBRyQzitoNpb7rh z7wLJ_skBVDl!|X$=@+NmR{pvVIyRd+R&7=`Tqp_6@;ezw9?I_W17_GvSc0W1@^P{i zG=stLt_~{WbyDNzGVRP(G{yDB1ifezXiB~YP&?vteZV;0<_fnPJBRLJ017nkauG)5!0Mg zz0KY{+k--Hln^(jnwQR_w$2lwA?UQke;!y?bX~oZ^4o-hlpClJg+_mJaEq<+;oH|!Tkg#cJ+7AHT!QrLS>!6;M;GJwJmwD z1hfje-=}S*CyV&1@?5|t8>OE_cwJp&hd2_rzslAoS%1}Pf0oh z-nf;Y^05pKF7xjJY*~AJK89>bMghd|@D_w`g z+dhnG{h{|4?1XOd4hw2;D$kQQFSD5adXAfK^lwCFJBGpFv0|O%llfU=DxlVyV{TyL z05KL`Yx(*tn`*bx1TYe)w)dm?i@9u#Zt`S7-gSLKVJ{Mn#yqN>4;!hr0JF`7?gD#k z!jFme*0k=Dd&mSK0K}Ah>>;MfeA-nbi}B=73#Yk&Tqvi%&r3&N-B>A*rhaip9~kiD zn{Jk^j-p=RT?&zP2~@0r7nnV%#M4mus7w`Zcv}2;NoWN~UD9g3j#Cx;UjL96@ocS| z2KzQVS(1))x-)K$1Mdxr-(&V4+3R1AoK}8?)Q}X8pp6laNh8@)(<(q{dl_YJGuai6 z-oN5goy4xfF(BOYPN}+Uh#RfB3Q(*Ec!S^^m;D`}4!@I~Klretgi)xt`n|}`ErY#- zr98(CQT}HCsdeu~9>xTRT+bOC|EBWVeQeeBUE@b!hb$X?MSK2cNJr`~03U2K>!-hg zJX|H~F)Y9WQt#%gxf$|?XunVeTwC4H&DkYf9)~xB+v@|js~`s3NSTYh|A#{ zpydUz8J-LpGIFH8-y~F&+u^Mb1R!Yr(O1cEiYd=m$A_gaG$@*k7@_SuQ)9iaQ}=fh17*K8lDPSfJG=3USsXNkjy}F>~jKg zVgF!uHbNS$RWHl$)oQFRp5-a}mr8KLru$*QyhP3QsCoKVMgwBBfPH^D=tUD6z{M+t z?+{eLAjhedw|>tCK8reAgtR>lE5IzfSU3(azM4%XewPl7h1JtkBkXljW!H0;Tz~6F zdLFPubh%<9KY#81R>__D5zad1@kA1PSH0Z=7rF&NtZ441<^S9^>CNA-J#;1W(L-6> zftx{xs$mNBrEAI}o(2IE_ryPjAPea&&*Snn^1)s1B@C=4UjT@1*hr=6dFoAH2&;U{Bj}>wS)95I+JUevzvOQNyP8#5WE6~C@^^~cXSN6Ue^Bw|vk-8G&>xUA;<48AXs zTGD*NjgZ_d#V}wK<^$XX4C7=?L3%7~c|&ep1(p6SjfeVP4nOOk<1`m#~bbj7^MxRdBcNgmY{v-fQKW<&O2yTQvo7F=Dqg zX-IW0hl~yyr>V{f5 zumIiSohS3Wn)cU|?QMI)&P#WL=LMl2M()g(@?F69rnBsZM1KDea<%~IDpY9Zlck|1 zml@5ic!?D_xlAw@cz3Y!VR2cqxdWe`bPt*J$IU93?*Kxa{uqN0|+>f5? zioh4&OTJg^Y07p44o}nRTk=xgFx_kecu0Q%jxtz|1Aj_;i-!Qc}E^pJb(QT5M~&7L15{C-bGdQ?S8n<5JYuv!1ukWm`S_N0(m`}5!aUJK@?PFa8v%3e-KzwEhQAep9b|(mL zrP=ZjLj#?7HxJ(W_+XRuwZ30Qi~U?f{Il_aZL_VkY!PrB!Pg@Aq?ev7RNs^vm$^j* zCB8bu2s!gYe}eANp>x8VRrvCHO+T6?_ZxY@)vIl5Al zDW*`t-jK2eWQHQ(_jU(%B>Udm+pp3A>xvzs z%hy!FY*`0n@2vJQ8PqPVGX_ha*BK8v{@t__J~oCONP@>LLgyXGRI3EJf$k3-kYl|U znbMs5g-6nD4?XB{{Rv8x=3W&q(wO`sa)wO-gt=! zE^!0TstE)){P*#jNHN;_rkBJvyMCY5&6!A`B8RxXySx}lOhbArzN)nvz>ieI*qWt> znkqZCxNVRe{Fd=_kZ~KIk-I$KKG9vZa_)-jGr$|FTvDMN=6mnddmDu7@*Ho5p7cF= zzkAz>GU`j#*Nhi!#j^(OEf_m7dw8R{%w)IH)S2S6(=c4%J9JPrkzYat&4k`&@!BQAIRDV%ou+GxbE=fY}#QhsNid-6f7 zqe^{`^EZ|QfVH#S`^xqU2~`Dj)ZTkC2ue|*J>6O`)pN2S|Jd;w=itxF_zdyhf=b+# zX1(xb#ny3e8sXLBHD-1Tz+<>|YN}F@!L=0&*b&edsy31t@cE>rYjJ#t#gtEvKf>1yO8s>NDU$V+)kAXdxKv@ zolS`*`lSU`m-JYXHL*Z*`s^Q;e_GIOf=Rh<#W~Y1dc-C6)=8w1cKU0a^AY+Bh~@^} z>x3W5@BSzR_c@LDi*Rt@l}+QdGYF6WS%h2y?^142vn8dx|0$6RS;be^%cbwzIP^)wYO7#t}mNw$AAv_KQy0R zI;9|ku>nKRcR+qPXKPnTa{Zt7tHO+|XK7^o7ya&MzCjG}fuZK} zCF8WsgvY;a9?6fIgY2~^RvP}Ph+grAG?|=DIj_`8+2BBxzJI?*(jyLjZ3KCo!8=v-%q{>!{8EFZm z8$b(zk=HN(X(X6%36&Eidnqvl7AOb@`$8J|!vGHg$1_{;UVqZhbmw!Jt?_b-GhWhx zL|Q#s*SBm#{^4VX!MIzcKSiJI2cWh9M=W}~R*wNFwk%Nk<_%yX2I>&ibhM%GjZC&8 zD-F!-whQ04{JMIuZ*z{NYfIbu(WBD{m+dM%kx4_twF$?%ZueX{r*Tt!S`}@qh{}3n& zKB70)2P{nTQdl2E9p(fTzc)F=&DiJ%;^4a@%t1W?xwUHrz zlP6u0KEMrw#J~$I9A1-K2JQa~trYZRanzEl4*ob?(X)n&n~CgE3dpp}o^8!}qcTDh z0DsgQK=aDq&5F|AH)cs8P8@l9#Yh>8o!!rOxvMvn%enus$msZn-I8t*?PxYWw& zW&Wq%2}G$~C)M0#-R9lyaS0sVHy_vHe%xnEaKr6))9dM4?-omau)6vIaI`tW9C!dP zUhoO(DuA!F*%1a%wyLc6D${p;!^B}3JYm`OMdmx_JXIr;k+B+RjzyQ!YYK`V6=~vm z$&lCR@g4BDv`{+yveKd$9af9)L@M*@K$o0(Df8xw;vZMv*<@SsS(9Dta6WM$mCoR+ zCl2ng0ksb&N%^SIi;pE>_BIx6Vjn$N(2WL@3qyS#tSIs0cBNw=X~Vi%_jHAPlN_Dc ziolou5sfZdYf7~x*Fu8NzYb@H&a)=uKA!itS;am22Cd|>BCwV^zo4Y4{RH?__JsHm zing$nTNaP(3cMP;b&|+-TuBN#{7cK=Ln9tPn@AYHY;+S#c`M;0C!>+9^=6ugUK_Z{ z0-7cGcDjlk>Y`a)SjcUBHq#Y+$BcT-G+RCb0iml~IvJ+sBs6d{l&X&<%TF(5FMHj0 zG70g&I%7J!mKK2Yrjup>B~XUuF|FNiKu!P=f8s63s|Y+v7?R{a z+zqsM=8^}9M8sVKE@fRILIpc954%aR_1j{py1$Qh<(87Zl+OTjjZ(BijLnQy>Fw>4 z(4Hy&rPjX(Gx?{D#C+AxKEA8?;~p>j(Waof0$%moWt}9BEmW;b^{M7Rly|KPjM(4W z>Jn9a8qN7beLI7_X{dt|#9lpUl%3&TQuS7kSBif3Cx-)>Uv}zB1Gl>F+4=)eT!eHc z*Il5iRNB-46LGf0I__8c&mC#LVFq&6Wg-w1&hDryO;8o+uP%G+$Wj{COU$=Y^vkf- zFfwiy+Z4Byc2FB8+jJA*snc_b2kEy4b3MGRj&W3SJEy)y=G}7qRU1tmZ?nwDzX%YN zW1)mdCZbd!{!Nzs8O5^w8-#A$wFiEcx-P`4`pPiABaNTN)4ZK7&=kwCZc*4w_)Jb) z%7=`Y57RRS>a=BbSR*{tu@wZ!*;beO@oyjTT~qd5&pIB z#Kq+|<=j1jg^IU@(l*C@OlQ5`gZ<7?7)vnAf@_OfIJ{zR2$XsP|BD%QbQj&ZSQ=R@SLJC)u!HhTUHbd6?NSzDs6q4olPID|D>DM}Z2 zN7r;bMKm&#8NH?=dUjK!6Dqd_JBe2XWV`(V%cOI;rNu5a# zGFJh6)7u2b%#b^0U}y&WKFHi?iru1XefmzYL!}kJC9C)e$lW(UvJS z|AF5Ifrz0}C)6Zr9mP(^p=a1~!zX?Q$@dC6Knu<)K)Vchf$;h6=TfgxU2H)o6V;O83a$+w=DoY6z6Xf@RpsvM z5)sl<>TN3f`)T7!qS;UV@Zy`I^iW8~hGQjxx(eKZZc!F0>_b+#`+a)_&%)`O`Sx%t z&(rcNF3{`VMeT}%U@fTh%H|a#LDbgiTu%OBi$!bKovE<`dFZosyWEP64%_oPoHp(FmJ3mMK z=b99&2hK|&zJkGt;J?wG5oD@4bwvY(n-i${*U3@pgiumvzT;@JHxwY^p=8*IvQq(}`lDSFF``fG z6$3Bg`C;9c4oM2c)19PAa@w$={6MEwBWSmpVJyC;|@G5#S&U#+Iw5^o!{h^IIxlk zR&^Zh!*}nHgW0ldIF{P^<_Xpp&VXI@eJWI*qX(iK)>=+u{uj zbw8$MYEz5dietUddpeUgkb91l=7?EX_v=-(2c4uXQ$3pM^gt}l8)&L6-<%B#vHe$< ze*suFm)$`U!1JdsjQu5$S#oZ^ak>b4zz|&r=5ysXCGu=!OQbZ&roOVwXFRN|Q=qA< zi7jl#H`YBzWl1^Mjno0VRBEH?W=?v3?^_{zxTj!2)YvIU8V&`be5`d;*ryT?Y6l$0 zLX~Y^Sb7o{&*wcLI=8R;GV4ct@W40nRU;RbS}ci=$>1bw)Y5r3c1f-4@zPPMRYB;^ z^><(C*P55jn`>VFFNrmRUEWFfX@ocHR1Xan*qvK4ph6?*$o=Yi7X%a86UDZG9DWD8 zayPP(VR2v@yfKov6x}kEcGwKZ-!t&!R%Pjy9bqk32<$f5rqOsdHiD^E6og7a(oNqs z08WLU{b&a_cGvjc3hve#z2+LzXq$N7L)oe`ERv^`0r;5hTno5hYUryfhbM+jdTIu^ z8#F3U`h|GW4kDG!73sy{{@?dj9S^&#ugeV6=>u_<5nZfPt!>69E6iA%bVYfh2{yF89g zsG%TeJKKI`@l13Nd?3K!$<36&LaJHON&15xO!lQ=^=Hic-U)oTkn`iUXJcn;?L@h- z6j>BpKmilXHGOA@1Q8B{HAJLfYFO0 z^OBn!&f4|LwCE&ZxXRyoK)lpR-e+BF7gzXI7XAWrwzeOA#pt)dx&gGb=l@K}R09dt zlkhJK>U8=TrTkyYU>O3J|Aqzk+M0NPO9)+FBG#K~$y)`0;)$h~PH!@G0Cb04Z{eBy z?Dq%6fij)tUl8FUq}h})__3jELus%SF>|Ae{uiVcD-p5kHoVDJ+>_%(VlRn`1f&Q{ zr!wALzmd;42JaAZSdO;u3dkLn=Y9$0tQgJNNf7`pS`^1;oS@t3_}nki>5mBPSPoVE zH!TzGb35-pELSEC%b9XFsh-dAh_lD$89P>4@aliD^JDFeCBEzVn)?A?7}wCp*y6JZcrMeQ$dFyY$ySvWA`+euE@5h-xti^(7$8+y{-*H{n=>8sB#a?dz^u<_? z67rNc?02kW8-jr+Zo9(SD45f?8_HhZNn6>yrGpu&6Ef`M zfD)!!l+sPo5aqSE0$`=Obth^|MNOIkAGek@Os=nuV`FbQ`sHVt1vGhRrHN0DrQD(< z18N1JC%47=bwYZsmKLH@vfLA;DqdD5)xcNvyWhpRGDFWewEEnXNNm-^OZ8qWtiHe+ z&j?0IQG3P-G8kUm*|XC1>ILwQT&BmiU>ylc=Qv#7`amzsXEP8`$?>!Zf;VzIj0E?cL!tJ`LX|y0uhiY4G z*UGuunzAUI;kUQTsQjV`h2Bf^4}yi+x&#?m{JSg)^%Cm=>kb_)T=fw?=3Kb2Ely71 zhx|uOhkM2%*e8`4H)tnpS~X=FjnEajK$~8ZqZT!KWP(f6Zh-dDuuK9lS3F5pAc#Pb zPR__Fb;=_zA1ur_NO;J9e++?zT|4Q2{Iih!lOYDy!d_0b6n@Fvuu&jQMphfBt~^X8 zFmS>E3eV7ukE`-8d)_y`3MLr-ID2igO?qwkv@9!C3{<*l&EWRV?~n_xx>tXA+*;+E zC0Sy_3@d8(cL3}rx@ck*=sRVF{f$xPBwLe8{8UZA{nHP^dt7&dPwz*yit?!-LnzuF z#-UQj^Joge4^j@!w6fqY;;1ltxSymokY+@SQLRWhOYZBGs+s>a?cz{Mxb5_4->vnk z53!wfhvlm{u+h#-aH7jaU^ku#bS^g2)HB_LjLRVKb(@!xl3VM3Xw5|DZM4O~G z3(MbN^DbOo7?ylenRzojL|;Sf#zu(WO@zH$DxFXjR#l#jmLGk1ZJVRm<=m*k?f%9` z1w~@krH#)~?aR!jx)yNTQONByZsCYI_HDNr(P+9%l>~Twox0NldE;=Nnlh}!l-VAV zF4mrZ8$vlGHdyuAS+BBV_)e-ig9CSi;Xi*+Y7-k*)VP}K(x98B^-rwd+T32l6A{Gr zd*ZKO8usPB4-UdJ^MWCvfGRf%6HySLR}$;YxjknnG}jwn%x*o??s9Tf2)dj1T+j&0 zsZcrsszBi_2xX-q+tBYc6P*+cr{S?~ZF1WH$j=q7Fd~X0`dArRJlz?_XPlC`{7I@| zapANw3A#JBFMa2B6U}dXo71DKM)=MO_QIEJ*kP2@sBuv1;b)(=d~}C0X+&7cgRdp|j0IHDp?xPX+QO&G9M_ zuKN*C4O>vprw_o5``BT?fuWQz#FMZq2M|mMGb*bh8L?x3>6h`C`RG}fc_6>;qIRnM zS0HtAj)Bq&Zf84MJ95WUaP-3v8oG=dnL0(VUoiH@zqiiW!d!akUeJCj{_6KXp=qT) zlf!uRTMW?2vF+oIox^C%2hV}vF1R#!pvt5@ghFw9z@|SsC(W_ajdyr3VLcWR+(Y7g zMVctyocWIePm*!Y7vI1ByD-~(zmKyKj(j9u+Wsn$B#Al5g@OpPOp~0*?UbHizKre| z5qp+87d!yGd9=8h-q+x;@Q_Va}=(?Ur{cVAOD7|Ty%aW(kn!_9%yHK zU0oS1@EmcboKdG>9J-f;R~ozV)$6w#$x1fhHlytHuB|wwCu4?Dw8JEuIdz95MtgW% zC&I7=@-pf^z1~7HLWq$_%Ju+NjpUipe+<(o2YMr)p=ss9u!^nD zv3F)L*C$w4H0Wy5tLmj}q|Fqt^DlOEg`j#u_dlG`8_z^c<|J%tPOLB%iufweUZ5VK z0bXESdzaF~;LUEif8ltI)`qZ_)enWw>lP(!iZami-D&&Kt2d9eARE4XFpO*>(_>gd zkde6hbY+C0FVbHXM)=1ZlRPMtbUSfqGNJD67a~y0s;m;m=5Y+>gzBs>JZvqR;w5;c z9tVQgE7R#fX^&o7fXtqRuW&)be_Banv~;47xvcKui6{G=m$=<^+h+WoxBguf$cU;L z)xRPSSeXedA@Yk0H!6a2Uyo1QUvJy6I?0B9#Yo~8n34G1%CrDQ;VwwUSVsE9NGN1! zBa}heGk7E}Im0}iKNwP9nPGjEH(`FE^lqGBS$9@QyzSpu8`nvc7~XG#=P4t+l<;Z* zdD6!g!dj4?`gJxu0AZ)|%&RvZz_ezGe(;Xni=&UqxEtz|6zHPo-F@vi=~=}siUwTs z(H5*g>FZGBFe6~v=+;f9I(Fkl0i?pGH&w8djhdn zw87mmJ8pED(4KwL=AA+m^87abx|2pmt`tmYV)#-ZpDQq;NuL&ZRxU8vodK7iKal6?9)pq59vqkzlt~U9s;y_ZHIO zYLZ^A`M(Z&vycf@K-fe}Pevn@S~|F=1b|0!PJSETC4?%jROO-V-u3ehJR!6XbvU?Y zq?reuVGN8FKBKz8SYul?Qi}K?02A{V2bK!JR78NZMyq-S7pNWm>-2T(j4^792mD{0 zRT3!6{;7B5c_|HTJayv-5#>H!C;q3jmm8V%5sJLu(sUmFtgj#n@9HJK@*ZIu6e9mP>T&`P&l5&klvwFv z3Vh#|zJQk!?fT~6v_CkENohe&1YoVYt)nW^pjMZ;ws`tB+G;jGiEQaaf%H0AUqaR9 zR{0{2VC9?OOciMMq|vyfW_l3H=Xf*c=eqE?SmjnoRJ71ui)GNv6Z8=Q5=ly&MTIF3 zAc9?KCYg?#B;t}Olh`dbg?#e3@0@2f9?%!jPh zxN3e3C}l`t%XKP&?eRf~Y&@tl>jP0MB*z0h0G@u`z@(FDiR>=oex7YHrn2PG&^F%WidJzp)7hn4=5rPl}_LXH(w$Yr)M-!U1c)( z-7fB~QkgqjVokd3*9pVn%@p_Q5q;{sS6Zk=Gu$f5=us~X@OmD8`VDvRxj}Swe+;m+ zB+Qai&)yVZbta-Bcqjy0URMmHrWAMzUuNV8e2QYL{2yFb-hpLlZW$27m2vL;ldG@8 z-Zi-bA=S@TB0VOw&hs;JXso!;AkiU~z#D1x*8<3@s2P|NYkz;X#RDsP32Gm+9?g$A zTU2MDxsc%v3v6T9;BtAq5!bAwu;DT;z5Pgz8s-!8{ywI+7 zy2j8K--RYH4?jI;slQ!@Ift zj$puWg3z>nfvpVid(J9c_kOp1kGcsDB5Ku&|8Jl^8ogYxPWH;~WuBQDEM)R9$;u!h zmHIcHNvMFsJsN^V|L>Y+IK}i@EK0^=>t2G}P^^bJ2Z%n?q$3GI=vM*AN z1(^j_g6=?#LB?hS@XpSAKpV%h?DPKopWfu3wpYcIJd`zbMwQDeXe)PRR>aov>cp5g zeufVNK6)#LkCR$p=*Zh?)mk%8sde$z9kB4;YH5pFdH{e4`+QWN22`lREWR2Lja5h6 z5nXc%awd^nKo5}jdu&~FS#*$q>N~(a2Lyt$o${VbyH$y@$O!~VetU(PO7IKo$q>H5 z_(AR5Nf@DT(d>7AWowaoT_vIxAE4{Hm4X2BUKU(OIipIN(*0>070;Alc}YUX#7f$v z;b2bN(B!hdO(Fndre)naAl(n$>q!Gp*1F}fmUs$=#Y{&bixw=(YBVQN_Mt2cVb4%i+OYTH<(?_gM|HD;~1nZ!N+zV_V36s9E= zE#TSYimB`aN-6ooA`A>vS9h*Wy)xd-Q}>$SyRGA_6RByur}N^AuwN`yH0EnE&YuD1 zAPt+it)QPUIgo7FpQf5YM@UlDOM!I& zqU*a!bV#jgxx)o|Ia#Lz3Y)h>)WM0PDj{-22V$@L?W_MA{<5N^97=w$j&4n?1>^qn zk~lJCx#3Jl(f&((SVU|?`@=VVRvElRw7W_BR2o;oD)FvAaJ1IFIE5h|%?@a0wEZCo zZXRw+t$HbXuSxlc4}MT5Y1pLGOvmh$bj>Isc_jV>bkl%NExw)bmO;^Etc2%8aJC`| zAYDQvZrMCE=Xg0}Vc#T{BB1E%DLN8&=~CFZ6$bdqF5~o&bZ2YNNv1eQG+3bm%0o1% zxVph_WB>7Z#uO29un)+xFZK*R{HywMdeS4@x@# z4?=|Pymy8-f>>Dj?^D0EvH;giJDr8=T}&ZFOsN= zg4530{_^FGPw3Q5n*}8~Lt@LJF3*<3C|p6i%{s^Y zrC}l1(w%aV2IDwbK2IEou2E(2q`^(y+w3s-JK#q%_O zBjop0!L!{}E$Zhej5$}%cs=j5rc`u&j|Bq+*X`YWR6&o+cO{x$-OHAlBc?F$gfBV+ ziJJbLrtf^Ub!4Tw;@5PpXl_pn6|u!wH-Ddv4CmEyXT3-8JJyDj7MZ4b#O_5{VxM!j zl{VWU78SvA|ALD6j7aF?zCmd09I|E+oO&0nY6>+pSSqd`sF9J2N;$cUF2-kwk8 z{F+cy2@}pK>_5~AgOwSa_Lt7>z`AJtT&jfq%$Vz+W>IFZS>{p%UaL@C!{1Q5>2g(X zG2_XAXW1)NM->VE=4_?0zIY`GB?h!Emxo=|{5iCKg8@Qyo&~Zdu_&r|O!myWwYK+$ zN!)P-mI@A-O4f*jFw)}1Di?h{@ia`|=xRv-z`MfIwf(iE>7KZESXDLBJWn^-879Z#B?M1 zu5P^Z(W?JQ7;?I0D7c(*E%_p9L+#(8S9d}P_ikHhk)B&mIW%nb5%#@{kSE!%6vs>H<1kx}NFckGys(Kta*7O{< z>E(NI;sH+Pd5MH~$Ka)hGqF4Ugy5f~0>-8a2xoq{0Qz350ybCni;*}&nZxb(IrULkoKZig zD~x6>*=cqH)&yT)c4g?=JF3GFSzVqN>_En>e=xRDZW*~+cRQPnwi7Bo71c7`6T$j* zxZc8Tw%ojz)y32F(6G1~Gd*%nguQF+Ke8GN2zOHb-yc2lfM&{N!|Be2y!&cbv^*CjYK!)2p8hl2DismWFHb^VI*<%CKyDf#!w zrc}N)Oj7R1T9J&(TWSSGg+6v=_hm3Kq7dPa-Sd5dZ$Q>K2|D7nlmP^2{F*z2%8x|W z+xQdS$#(@z_kK1?dqb#%3sxdIp+vw*BDdL}BIYMk8(lHh`gd!oI(eU8?4|yCzz#+! zN0 z_tKn<-IW8-O7lC?HD1Uw9O+spU=k1ry;Jz7+uk8ikgo1{@aYl!^LaZQ4iQe1em?gA zncY$`9Vv?#hBvY!q_J2A=yjaeRNG+P>~;%>JW4af61-Nuc_V@KhpYxmRGVdQ%+x!h zvI!`Q8K*w(U4+jvp9_<(Q!m#0t?Op0wz|B(8LsK_#pz7xJls--dZud@G1shMInEC{Bc&iTJq|0c6I3#?Yn%SA$%ZysX1v` zP>Gy9t>;!Xzl|-KXtqTOs-X8a5kf+uPqS)|~Oe8)GcHOV*DEDmj{;-_FE zp48f1Zn(e`Q9KN*zxgJu}R9Oyhe#&{z|VZ@B)AtjzEA{^oHt1sz>P#y_azeYB(ikrjLDGRq>_yMSJhCGUCo8jLjY z);AU%{elmybCJBws$6cHq}4MB(Tn_Fl(8rI z`KilcGWI%}G*g{CnVCLGRgk|Fe-D&AI)_tL0N2#915j%ZpYg z{>Z>;5ss3M7m(Gf1B5{qyQodC+~%0S;~wQ{U8LAA`GE$|*NZ(_=vT>e!8^78<2e8i zSW5uqtBA^|a*w3W`*S|#G#31jze9ygn;uuy9R*H#6r&&B=vK)AgUoqFmc!4D4)H|f zJj1`yCCX}m)%_MduaJKum#aH_h+qh&K9X$imz;T5+0DF>H#0angNZ9`kcd>J9F$W4 zgc?1>p@KVP0412EIgVN-t`Q|G{4Pba{CtbbX08r9b8z9G+)r7KMBJM@vHG@}`W)iQ z&l$L80X@n(+WwfxkM0x8eQo9tOWGaT@vIiCksv@cB*JWLq)!8^OJta%H|MIyG(NQQ zbC!pk;MYY?HUH=11+rb#M`4DbRYl4m;8)j^oh(gU4VK=Jbt2}i!+h{!-q&%l|yBBg4pKCYpAhYL>#$+{@Q{8~} zSVjquGuA4rm}>j?q~t$RlVK?pT_goP);l0_-Hw*kKNvwB z!d^)jI|IWzh*9}$TTi2O+bP>e1ZF@?Ii4~gd5^I%Hx>6r%Wcs%sua*iRK58!o=|%J z^NR40fw)nbmcU{Bt@W>%eQRVC5RHkpTQje+Xyd-L?_1+O#SpE?)|%BAVuii2I032o z*e}LFX=3B=06-59f@2Eay?G1h+pJ`X(MKQbi2WBHKy!eI=s;;!X3-}9X5R2H0cj)p zF}2XHin)3I;>bUr^dd5Yje!}^rIK546m=0dosAj_Rym$Rj zlHo9&fCQq(9p{Fh566kt5MFSU6k`w~E@@nXFE6u* zu=AuWVlx>5nsRxqmCvEivTd<=W%5@afqF5I<+b?{!(v|U*9VAja;RC7T=a-hUOZ8$ z!fDVIDvKha+UWyxIBg*X@2S{GDVN38}EdtZd0mNuDo7UeB5L85eKI=?O|g8Pbks(W6n2XR`$d z@ebkIB-pLKl(CErTUqf?oT@!QVrMs;3n z5KB5Eu+?H?b@&-R+%fMC*uk8xBZ@K+uASzJ+jf>dm8m<*B^O0F`2cP$!1yNyMvO7slur79V%pg`e}6RLB2zN}*@z8p zFKwNppVS}BF;Y_c9#=-bs-UU=0I1{JPJq#bkS@>Ydonr9Ec&K|+u13*u-AAR&iWTY z&SY2tW&bZ0;Bfz1X|KBDs}!ERGc%1`$JU1A_1MKR&zSr5RuaI3JKM}>RQLJnm22C- zq6kSBWJ!43tFFh~$Z2q~%-zQhVOJEvotXHxyyqId#@4mr5oi! zq#!6V?L|%5L5o zoTVQn_)9xB-hQ(~-Ge<{PN3*xz#4GP;EI0K`b1au4ELwMr7Hm|ZteaR5_6sWxflw; zLLj{Symv6HVEPWSJ&B@v&&SP&5wYJH1DQ7z^KycbA&m?BU96e-9gL-;g@&wp9hex3 zAdtWl0yf{jl6HG`SVEx@0ZxTZKkIn3C-MzXj5pDKMV9&JINgs;McO=1nqxR`xM$z# z_O2urovL|lW0bL78syr5Or&Bdt(yr=hE0iY_s^w4=g$efS98m#zE?|zSXGLw4#vR( zg`c+?IOfu|WQ;O;71P3%Rfzt=3KVP@sCf$W zH+{ZaJ^U4pRrei+h(B+gO1y>j)kD^$-?S%R%;oGnv%#q64g84tSmamDz`3xm{#JFt zN;Fc7mb$0ARs4jR@O-2CmHUaADZD>QKsSqlw{cXy8#n6Wd%{mhA(LQqa-aSxFSrLv z2*zG54+XNWyc+B+rB%N3V*v#tYI)}Kyi!=ao|9Aqi~QE$wVAfW8frHS_lVe3_r+tF zeVf*K`s7A$pS{3s26*LU!3oVBE2tID5SN*`3L8VAgif0ItJ>4|^7Xnc_7gfHRjRSIy~M5CGpemYsBcU3 zp{`doj%ON-O_<+!1PLt(|E`!`PehFRmdyV;jPfR0g?``qaIUj^8$Q2?iy#hv`aI9W zz1=K+DD2HaTLS6)MW(@Bk@r-8pl^N@0IvJqzbe2FihfjXNZ;*k4uxKW$*E&_p_RQpnjFi#E<+9!i)N97kJZ%Im6Rvj`bj2em zP|P|Es2N6@emF~}hyiqk9Ji!qaM)IlQN1}3t{E5{R^7^kPtnG59|{X#0#ChI;)oEt z$A#iRw`;D*B~k2jtOZuq@l&oFgUmMTzYNSjIuWUh+C}JmLG3fGxEZLhwE#z7F5=pz>)zSHPQ$wiMYShCAl?Z9l+#RZNtY(^ zunRV!^Zx~E#RmEKq_sQ@(8>7AB;t+Z!LiDe}0<6yqd)6^3|9OD&idO3cNH^9>1ch_GF_G;nQ^D?H-fwjD_yZ;}yI|%zDn3~v@aIm69={;TC zzKs+lL;A!VwCLF%$B)z4?)Jt;U&dmET0e zY>_{Lq>{H11(M(TBT0GVVhowcV}sm@P@%P7Aw+uyXR}6tGw=IjG?bb~rs+rR%!JyE zI>$oNj5p?rY;OS*gx8m#%`o}AB1Y&{=ezzp|6nSO%a}Dg647qqMD^qOA*B^l*0&Ll zjjv(keJo^gi;T=^o22)CM}Lvp{AT}clNWF^Z@^-t9$2c=-RvYBM4=Q3?;+uz1Al@Y z;900>l)({nOZuhiOB(mbuTuFm^&88ITMVv;XfQ7W6{-i!xWWXJ)!|0vQ309gq-IoJ zd`wgjNJ$AVW9ElGDNp+p*3>nEtUCu6@_xCknWQj?NCF=BBgq^VvP2I2m@@s+X#52G z)_D4+qX#i(!#SDHxVDlrE<|&=qcHGLS;;N+azf;t)dh|={U&!gBINh&C&3nqC5qzX zB<>0X;-af&WhGCUDnZ>Ry&vx~0g{QTpil!^#Him>?kmt^?K3T{5IX#Fyeh3;42)oE zzjngbdViz$o%2T zC)4ZD9N$bzO6nU2rN`(*KH5#G(iIWAT!nvMC!YATKOu_msiw?=Ycb&pwzB_I_ikYH z*1z2?ceX>!&nR2r0S%tqw6r;ohA?q5KSYeZa~&(5c;@X`FE*yugafv)0r_1tR@f%2 z)pg!)C~HrbscOvKVtUF{1}N>{@UBADpYM`W*l2+dCgM)V-K>DVT%eh@KbnSI;C7Su zW;i8W_X+#Wl_NxtcbyG$sNZ=6maYUDMn3QVNZ&ExfRrig4pln;0epZKrGbBb-Yp~A z42I+bae}~2hzZWq!{lJNj2tk5q?7!KL*=UmR*Zt(nhd zB3VjiaQ9!0Q+#Tp_DB)%Tvsr+FWltkcyx0l|gFp{x&PaPLwBWXg-m z%EEwwE#KO;CB4BE(Rpqbm4qT0U@SCL(A)Fq!MkRHTwEb)dG+u~#s|1C10ut&ro zPw+9xJv;$Bm181HzuNWd5@=q1&12;84ou5uNhe>LW%n{+1l^fdK++PbpN>+{c=U1^l&J1(MTZ!7o!tg+&D@2BMRa=^q&M`@$u zGC9bCM0lgQqT6a@&bP2QuB(!jx~uCVyvOKeb0j6Zr!^6j$ErZ7-$N8jyq_yEXRz&@ zEl)&1%e~*J*(i!~lrR*$2jCsIt8}$g+PKgJTK!&(aoupsqNVNMDGNsbsSD7#8NM!B z;jr_rT_zdT2$3I$8>a_|>a%hfg`l zqA5Sj;A(w0-0`sYVdh5^BC!E0%85wKq3=gYg-wHC0@9?wUwWuD)R0!B(3a60E3X;*?UIYG#a$Cr`wB{T{Ji#O@3OuSmnb|XldnsEe!mRn7_c< zL;1X{Az;`$fu~wTS;32)F&9?>6xIJYgk^yDO|HA**H4Y$#Y4sfWc@`759X;(Bos@t ztFEi3AZ$(7f>_|CdW$*rI<|JSE+%3vs=S;A#9okLB9w(IVgR1^iVXW^B2PO{ESaa_ z+lq+!06bql`0X5@@4%+L^Y)U~k~< zktN>PTL-H4*5M4mr``T&vfZHrUg!dXd`m21W);YwweB_q^VC-qgD9g+IK&s&XWuJu ztZ3^1ykh_P>48{ZrVTL84^)&rxT*PsChf;L=jN@}E1w?xTviFIu$Zy3Jhh*fDe+`Y zaA_=${;|Ms15F36?zgql0gI!h<^AC`=|`lmH32{SonZwn2qRO(3jsk^V&OZZJPJQ| z>9Y&w(2$FzV?5HvO_TI>c3s@dR%BNkWb%_^X1y)8LLyE`3c3>^CrU7F1BlZ?OtRBX zY|F=kZ9-B#h0YMn7P(alrPmAAk*ihym?RQ^=p!5~@m`*RNGMN)GTtvFLX<#o|5K*J zLX#-#pbxcMuxQH~MP>>D(OB^{PC%*|BE@eP7+E8D`5#GY#QFzCMg6xytgN5O_Y<&! zIWYREq1eIGf0L#yvh#)9iW(A%7%{BcEy<30=qDZd|0I*8R~4V zvVb1Fw-V9E#)exBbR3yVzvAw=eA3;do%YOJ8GSar7a3WoLEXp1x zL6dJ;ZAYs>wMrI$3mmbJ_U)V9DE)s6*H+M*HG z*)?h2(?bJ%#S2zs?j~4#Gku ze2GY=2Lx0+J~!*fI?YP~?7)gT(PaFt3Z=WfMaO{LFAbV($n$P@gG$X?sCj_j<|-S* z(KF2nf_9#4WnU!NcH3QA$LmS54t$G+B131rxa($<2e#geAy;%p^NWk7zWu!lSK;R} zI0t;gK*y-~&LF%R-~oqbOdPS5vl>-olA*N@MxkN#$BNqi3HC;XBA(Ywn&o;skd&9h zz^3og#o>wf`WA<_<+bJCI<;Ry+C;GCirn<404(e>o#)`5stAI;Z!x1lb{pS?u0<3T z9BA(#JqCV0O+i^FQwA1TR2~Ny+hJ>epfJxo` zHEut(re;kLbuB(;BGMdCo&HnC_gRMBtNL3?IfD+jb9}oDE)$N=!!nNE2ITH#eV7rg z9_xbeT78zSTvj5$oz}FM*4=QMI?sc>Si|Zg+uOlK|LVif;a=flA!F-pX9Qs8hNJwc z9jgz0Zsm^)eXA}8TfbIcUcM0PL;k9guJ?H__){Piyk(2*d#b7JLvlyeKwDOflT8IP zdufYP61m=xT5puTw+nhiQ8efk72OL)w+Tp=)N6F0#88#nXg{sTYK)RlV9AVZ2}>=f zk><{a-sInK;F!(cl^SY;$ayD%!NA%4H#y&mp+MlNER`?Ma(5@7eKCZXisuzZwzV&^(8ct8 z^eg&tHoCmCy)FKS_!WPBTGh)=#J*OrTez`~hS4FGAVw8PHzz|kc~KpI4a^a}rC1zE zw8kS5wp9b9H z*>Sm#<*;~(e(HS&4=t_nzZY}JsN6{SwfYY+67PhmK)C*O+#_x46`(j#WrmcS3CJ%>H3dBz*`&%C$+yo( zDIt``ok}e>qxE;Ko>%(CM}W5q7iN9h$kYC_8!v92H*J{4EZWafFuUk@16E4OI*g3~ zXU7Ks;^`n?%v_2uf%toDlNk#R$$7mqe%jU>s!Jqn=*mhdhL7{Qx2SJHOCPKAj&BTR z#V+)=Hf*S%o4L)X8{BokJL#nb-eT1%zP+r!I;O)bo?&ND-@wjSo+Wpo7eNYNT!J(pzUL>OOu~;)Glj|G{nebvIcE*~in(RzLky zf|o}VCit3napO6Y`U9>7;?vAxqk>j@{BqOdVklJIk;QNfb;i6gQ0+ouzQt}ioGR@)D z51?2UnXqk#LoITf7^rSd%o$VlWeFrY zzR7Czc;oMs?7+^mUVs#G*m?vNH&8$mrxs}R+e=%%zP{{HPk!~PRmAKp&}(sI+{;S`QUhm~K5 z4Ck3BGU;g@TyFLbxc$n!g;V6(1&5rm1Gs8TdRN+fpGWuSqVRU$Xar)py?pl#hm1uQzn~{+YmV$bijbwD898Wz{Cau@G za+I?iJlxQ)37$z=FA&AQJ+3%94;uY)?Qzw(N{CNY5$)0l@mJTqyyiM9zC9dWR6FSCAHOo?Y%-oM9qQ6t`Mr^Q$gLTr^ z|MQD1BAN7F)i+<>v|ji-+Au9`m;*cia*HBv8RU#a9YCU3XwuNr-K_G$|*sqfpYrUwZwniMhQ5M>sNyMlBm zRWN%P*Bu$gM!ROqKs0(J?sIb6+FC6WpUGuB@vme*QzWai>pa=P^1C~nKr$GOVx&8) zT?;Y5gAlUrVM^;?{CiTK2gHmZTF~cRnjH7G&&a6w_TmvTDf?U~g(h9+C$yL~C~r*l zY?vLt>l(Nl#m&VAlUm3fAG-{;whxZ&-$IE)vljEH+w9J-W}}Et>pDvOYUXW4f|B+V z9PlP{E4wV>mlY@>z>>7V*B3s3nz|GS73pV2+)lq6xJpq3pXL?gmGhxgyY=*^Z3yv1ZCUt8OA zGghPE`bB&ti(Hu5A2aQ=q8zQhNJN2wH??iFWdrzdV>8P;>fcBhgNjW;cece#^T!)MG#E^xRuFuwi(ki`Qe9VT6?FUYE10UO zJ)^r|!23y@Qq49{CQU`u`@#HCppz9Ij@JIgf6Kf{ra)N<&M?}a=94^#lCfpoo)Q`L z5uSuPi>e*OgDgP;;-voJiWeqHPl6kW9LkAm=>G%x?Vo`x5DtA8uhtPemNLD?Z5~)u z=r^xQa>gf*8D@s+nDGJL&pFB6#(WLDdh{acq@q&1zmUM|h|umGxa^PseSc5T1$P6A z$d|IX)a%d&qUF9N%~q^EU7!Zh1IHs&%ir)SCrz~Kc1;ogqB_OApgS!hwy3EcV;U^9Nbbq+L1^R3t% zM3v%zgBGw0_5WZEDAtDK_jY0PGW^6)*lJ&h7_Q;3@Vw0d%7KD#W=7g#1JM0H`@1^8 zYTUH6e~kw+}5?WMXA?cTM9kCP@~kl_T+xph+xwyYTZAJY7m{2~|&56Kj|<1Z0GQ zE%x(H(yAr9YUaeS_J-$E(TWTgg$u4Lf9Y8DXEE>vZNBdZiJWb4zk;wK_8TAK}3L{H#{D1NMcKCSa+HNLjAa1a{4~Z-^dTBV3O>k9{g}Pm_Jz8a=V0p@s4*~ zWvpMzJ~gngbG_>OjDo3|56|UaO;g*3cyG@RG)Fe5^x{MI;q4g@l7_c@s-p=VLQuc; z_-{w&ef0wxm;c7%T`R_w4&U7`_PNk4Y}YF>@^ zuzR*LnZ$*2^YFw+n$JQP_0vf*iEiuZWhnyNPx$$--gkZx3qI%CCf;)Xh~_(GyQC&%^gyU@Cz2BTw^?! zUDk{rS7bDe4lT7MB1YM~csiQ=5<0X6p0gTIu1t94z6#U)N>F*ueZ|M^N_^;}Lu6Qk z0Fb}$@&m3r@u;HTAri^UE|LafGKn>R9sHI>yC^Wj;Wa49R7F&m26n*lmTE@ok=A&% zlYGF3blE5Yc4C(q=j+^>cS65VbPWP`PA6pPL(9Jh#at*8E^t)c9SkFNNYy!%=w9VX z>C&128pWz8dbc%ZaBL^Uwv7_sUfDW{U*r_D?i$gVxQ!}FTWUWaQVulQVW2J|yqW_0?LtQ8?0ZN{ zqux!;KXVOjFR`lZa{^nmG$~z5g8rL{3J;AI-d|PM67N1L`PAGUw0aZGry>~m!T(E) zM?~+a3>7-Clh_MFBsk=Kkk;@G>6Gb>@D`e&&Po3+oS6=@Y}Btu3)wG z!>zOK%-<|pn-?=zv~2F5!QN3c{rWKj{6AkQ&2ysZc4bG3Kc%;G$N@CJk z#5$(Xo2d>phw+3H!O)U)jW>eMk_~X?t*7clS>Lbbe<$Mm*A>4m63(taykY%c_Z;nl zJM%ueGC+4A|3?CP*jLon7TC8}+JcO_+WyOzvAo#y3mT)jSMy|afa}i|V!tn-DJP{g0BT5uIg_o@*h#_HR*T zpv(d|mj`KGA%85%U{%vE6|C+26Lom=30|)7DrQO z@ z`@WSmi)WHlDZtX+G_9&sTGt0IP^uRwtgMbdqaN*rSyDnnz+VOL^8Qh3>)4_1Cu47q6&T{Yzc%)O~eD^;4wW?$8 zQGk7x@oC!qX<_Z~uFf4Jn$Ghl+a&)?MdbWL&$Iy18Hx#KsRiXksP_Be*)!Za7Vd!4_Gq+H0z% zxNuGy$O7P2u=(&!#w)2Mp_GndA^#y+>M$XjpQ16h`jru!F~Q{p}6UWT@bFeCi)zSP}`<8LHYJa ziG8jud3#LA!r7WlTmN1)zlB)(A#2qZb=R-*#&Rt~4F(q0Di(G<@lNSpPu&r~+~A~y zv5x;+&Q*G-1D-ZiCb@6{<@ls|9@_BGIQg&0Dav+PozxOp?tEl-&!u+LRnid zYZSkc!Vk(hrGOLJ0j`nk-EfJv@23AILvu1JlyYqC2X9m0$5;9V%ycb+_Aowusd?uu zBuuEZJ$99x+-Z8w0V{f!uwPNpcl zPu-JSSI6bS!L1tzZ05PmnQp|fKuP{E$nZ?< zd7R8A!O*WAnMS9C+GKVgt^k2{97Pl(xvvz-t@)BGF!e&r#d%vEq*X#Lyy`G=fyR0L4byY^^rPGODpAD8C>K&Wt zz-vm1{x|yR(08c}DYzh*Gq1%z)z=a@z`C&m5+bN4H24<8-5wa8;m!8IJ>+|*yG6(>?>g+|dvE2}{$X3(vkKpRkLcF3x053une5jA= z9{Wp)BHE9L$TugQ@r>jUsZu$LHE<*2#7n&qcz}@Q2>-3TuWjM=3;|Zu+b2C=8iIW0 zu=1^W-wGO~UD?+)$sbQhz9e2^t zNrS58Gt;Pk_ZzSO@qCS+L#ISc$y3zp=Ix{ASNK6J6m{fowiprxrwC;CH=Tay^l8Mo zSxbw^-;P>~2|JG6Xd#2T(d4U3|0=*!NtZ6(FII+#VkQ~ zd*(Cs$xix`Ls=}ildvslsYs*~3URGpvtEidOu}j3xO{9`iIPpuY!4uXB*Y9^H5PHD zieM~)(AFb4q^B(+w4U_8g@2%TRxS>oQN*|7=KuKQp?vfsfC4~^M_e6T*q>{IM=+N# zeYnF*>Kvx=MYLx>NK`WzWJRg-fiaCs{Ma#wGox&9l|6G1^6N&Z&ZN<--Vk~d)dLPO zVnXyj&;)o&YXFlz0p)pl94R_7l~JE!dp9O10~cF&!z(uP0Mhp4Mq$j8PvIL?u~q4* zs6O1=4U3o^lP_rD<;Z7#jR;jv6PH_s#_yIs?d#b|fNgf(>#&!WEXse+MZ{l~>W+LG zZ66T7t-vnm+BipFIprj%4v1g>`1y=spFrSHxLnZ&QO9Q98zwrTQ^>K*dZb|C130Hx zYyBqR@9@Z{?vhjUhG_3gchLvDVq~vj=L;Cboi%W>z^5anU}KL=9_ap9osOOe2`3H! zgf)TMJfj0z(JB(R4B_*G%h9j@HDVvYJnX6lR^aFHd4RltJKN7k@-4xAc_;*NRCz?F94}CVEx=% ziqH_8(Q@2;t;#v{d%>NKX^s=OQ|qVGGT6P)8D<7e_;(S?W-nNMzW&kt;$oP z;U98tD^IS1fu?BRs(#wtnZc%K0Xh3M#nmdf#M%xyyTomUJyIZE1{q2^e-?p%p6)+w z&%|WWCs-3$^>Jn~Ixlp!4RjeRkUrlTpT52PnYku2H-MR?pD}@+aqtQ9bBE2s&bMRUXgp!jX!n~$}Z8KNY=a$bCsAwaP1j!C{hKArHSeS?$anO1&jwy zBwt`N@$~_*M6+VNV|!6OSO06|*Whtuz9V>*LAUSHJ*f=-ZYNK5tbqZd!3s+oOw*Tg zv)QM9^vUqQCo7r703>HKRE~A50l&f&DSTSDsV7o>}x>a7vHz1&V@+_7e3P@rtlJ$zsx z|LP--KT$TCDMw`Mdg{dLO3fR9c(Y6e=R)qKi0Yfo)TAekLtu-9pz~fus2C zr-bkFJ&Sw~Tlw(MRPv=RC&kN3ApFcI|Bd>dNujf`ZnoxV^j++!SbXS!7{K%Pj+*=z zL;6NIhsOsc%<(qVDVUC^Q6IC1z;n$`qFHv5{alT`?ZX?3VTk+3wZ9!Ixe6(N#qHc< z<>27Cg_a1Ih1?N`90)#F(J5?Yv-V84wY2x!dh`iwPt5qWgX%1tHs9+*zSK)wmS^6pANh|EVAj!`QLtPWvNlACrjx3 zHR+Ny&IYy$AJ^CyPC$YgGRF7Z52wD4ng$@C@gSelLg{XR%rj?$@biU0$1kE~x7tmU+dr_*200d6K;fUnm!3}-e+WQIYn{uER_3Gm9J)T}r6PHB(%Ni(*LNC?N zzibO{wSY`=Z!;pUOWhMo8fd1br^DasAtJX(0)m##{2xRh{9y$0l4O2Z_HT5(8u1Bf z3jFvXD)oveEdKzanrr5rot7|txBS5l!nkw9ZoPP><~;$vpE}~0#-g;qi7Y4&H&9xA|HIWuHCI4!nj$-sQ7XJZQ`XVBNHva{LrjAjeT%#XWAMt`|R48MV**d$> zE6yRV3wBUnbu=rgW#8RLDbB_mEy%IUfh+OHw8R4~NFS=dgTP9@RllN6n^2?Xu`D%a z1$vbU+-!hT)ssMX4aVt91I;|`s1kbjbt+9Kw1p+xb}azSmc5ZUUya*^K1DZN{?Hcx z%7r&sn>IDz&~W#nALCKti}Thr-t~BhD8~uAkfi80)>O@s?7$prn^v@WU%SX`kB`&u zlCPkl;Qdyr&}lyR!*R*zT5@01>j#YX>z*Et=14fab!OZNkiSJ#&s=a5s+On!277Cc zLg^%Bi>c^Z+rMI5J&LI%Eh%(9kF_aXixgPBF8y~)29c(<(8gxSxh^qQ_0Y6X@TO3ygXqmw z?#6MaJAY6Q{0P+y3SnX$PtkH>*<%}J_~kC#?wG!@!Kr54`Y_vntqTw z2u6%^J2Edczgxn>T7NLn&9}ge5?gX#dhLDO+;UnP8tA;@0g7I4V?ES|FKMmw5PxbZ zhK1dm22+hfhb~=!ToC8Z>CAtQJYO&`70!O=uBb4kBW;u;*F$u?p3&Oz189Rx|doq#UVja$E&500k;CRL)q?4$WWR+e5YyDYGv~@{b?!Hm3EBE>$pW2(XHE^|nF9?zi;I#Rs z-c=M9?tU)6fsTG0nu$`?lhGUf{E^_t3fWup1m8oPgX?2jf}aJ{(w}Vt$bY~~o|T4f z?7@CSi?6mm>>3sx{I}`WWkW-Wof^VJL?!yDaM9;O*|Ce(pr`e-fUD2J%^`ChrHPTF z-ksqkz!Z+T4QD$yK*kGd4Sn!W4zyUbe`joDW@k)Zfjj`D*qg|?PTF2;w>#IK&{U#C zqqJJoh?&m@m-7XY3zipda4TC)>I;y>TuOVOjJsOu-0n~g?vbC=RHskziadpX%{Qn& zB(DPfiVVh>dbl@dx!SIg4lXLUYb1ShE-cW;l<&8TWvfv9@VlG(0`*g>FIpaCLDQnw z^`f`f-@iy6A)R|Sx;LNl@#k@N^N^s^KU^5=zcOmbKy6-_l+D}OE&Juont@Si8eI{) zI-b2_@fi+cLw;xgTKH$=vqi*tfPpkLvrqkNjXYX>7fAH5J=vir5|88ta;8;4>s}C- z+Z&@!hlO}6S##4K2|S#d{%GwLV#HJH-FX?7?mi_BE06p94P8`_QhU3)BCL_l2li?V z|D;xNR$UF7jV6E;3hJ6JN31p zSS|C5uy<)OF5glUBx*xsIQpHNK8f~xD?EPFhumkoHr9ybb$jCyygLREf$;v41HHdd z)s^3@dx8kkLvTPe%av;;;>9Dk*!3eEwy?~{r6MNvd-0`Fx~{1eUBV@?)I^7toyEWB zHi_(6bv$XOWYyST?Q4^@A>L;jvWeqVPgUMJv2n;B9QUaHLteKCeq&NtkZn7|_&UOs>E4L)etXS5mUc6&o&=Mc$b}9r2_PC}t3otqG7SsG zQ^nu&WU1X+pRU|{`P9*qULh3R;u))PU|~8SG}BlEpVs;56#6r~8j&8H*Hr_R z(XEpr1}3c|*(evLdad6-csta@BD5K95-#m0`NWx)#7b7&pWKx$JZaJt!gEIl1Le1{ zWVAaFhr{mnS#3?mieEXb|9lKK;;evdSN0Rjwk`5+dTu+g|0^_-Ij=!sju)o}_ejYT zt{t%FNz({jV?3%^&>LkHGx>;RRPL$jU}8hOrqC^FC+Jj8n)8>`a6OrpbSHUXN=a*H zXH~<@Y#;*m_zJ(E;uqz0OP(9VI2ME-y3x*;FL1NG=+h1;+W_;&rhZBkL7;#(5L{rB&%4{Y&ILiHOpzXn{9Wc(Ba zq<>IbuAfjr&d;GMUd5Q`H!<~p#YJ7J#1Nh2>Kde?aTM1(LOAFN;Cra5dUxt~l)H&rZ=&Z^9bmbUv>`nI9v7tarR5Yr1L>hAeU(bBN;N7|38 znO7i#l7qLlgpc%beY~h>%80)cq1oQ@IX(f+JLpW$qlxb;-H-sVdA%CYH|*e83#8;^s5 crpVye!-Nb9?3lnR4gy~1PF=FDvAh}cKOp#xiXeg@(!wYuVi2!l z83+WTVn~8;l{O?qE)Eee2`wg<8YvnC0^E~3@7H%e-w$^^&)(14zw_T~{rCEI@;u!g zm3C_Ggg_ul&Q52%A&@Q2vb9|fB#=E@Gr?W{lD(Tf1VSl>N<$SO5IKma>v;!rb92qa zOwFXs{YhEgP3Nxjrf!Z*XOB+jj?NU0&z1@19()l$6pH^Y`ucowo;mNY%kxw7$;BX=xC5|H`u4m&yGFXBymuA*Hd+RnzN8FTt%QatU3U1B^9uuG1o z1+{`l_bPC+s{)VkATZMj0yAZDVmvZ^kU^`YHv#Y$F>i^iqYMsPn7|i{aJ3`TBHV)! zFv}NDiEydn84)f@JSV~hh`)+(E^iXzk=k53tunu!k8y98fcHZ@5CjsnfynaVa@oSD zIZ#%HPl%_T=%&*!Wy`Z|x+>u{c(Cuz10ZNM<7435-vBt_3I;)7S-d2&g!{pJFAKqz z$SzQ}>nBhVMW zE$r$6y;g^V3bRE9jkkR-A0uvl0Kk*a`ydF`&&foVwihUqkU-gWA5fM)4a#(Og4L{x z064YG1wr7ReL-Z!JRV>R#Vh3aP9XFEcHaK@scz8A`ABRe^wx>BW+=7A6Kna1^%pDLu7hA^BdKhkjz$#Eu zZf#G^%~i1(u7IV7eb&K{jR-SLAst5}|3w|QB&v7=-9_r}oZnAStdQo_T*Mn-}g@r!p<6HjBg@hzV_VqMr`AJJtM`Ts+ zjqI5O67ez2LkOXpZ1i0E_WfA*Ze&)}zKn_ZMLIzc2|Hz;K;wLecb8b*#y(1y?tipz zkOuP@*UL)hd_fOVVIE^gaJC!)dawyb$k3ovt(gRuetHGlmjSB@x*SKE@x!0fz3JT` zz13heIK`}O?M8dC6ZU`uW<2B!tuJ^*-=Xel?u=H^!DY2p z4y8ns3|M9H=5m79RVKnE>#Y%Tx!mP091BO61GTiylJa%Hm7RufC_^f>kFHDk4> zJh4WcK<$Fau?JXHtaX2&Hu30Ke%7y{#clJd0e?!GN=?c8cr zAdHGLi96CroS6A_n5^cjc4u8hwS_|o(k35Jo6&u;JYg&$z4yt+u7!OA5{>SG91w7I;%U;7I5qXwg*$GUCdVOPu2b< zFk<41ys=&3Kt2BWQY^4dqT@8x=|5YMgF-b*oLm}CNA$xgD{fJ`)#w~b-wuySkrZN3FJkl}AirB?Z?G_>4}==)o|a-!sshj21;!bNK(EPs4^{N8^Gl zMM~{vD?`Wad;To3Cxo+Sg?d6p_YPS&FaAkOL;8(t{w#sIWxw?0&k}n=Ke#&oAI&jC zJ!?^}xYi!)y8n%f@r`i3}Bu9QzV!K1v|_TGRdHsM^L=ZJEcd zLl*X3oAln6P^+_BNVm_ekf5@<2OF=vE^RaJkYTy@F6N5$fAAU8n5R$MR9P~tAn58@ zHJX&E!%eT=AB}al5P{SDWeDN)nN{b9P&23r8CSj5APM36RUXPJl1q~wb?gWmzFhe{ zv#k4E+JYUUOJK93*Cs%8<&OVxIRnFxNs4!dy%JG0=DNkz)?3_=jqNwC3@D~3GS}G_ zvlY4VEQ-Xmr%m$faq~Fbaf!~sHEILpBK!lqYvOd;X1tCC^jw7CTR^nksnuhDM0BTB z2Iuz|vo;^L*7;=`{njz-xVI%#UhC7C=1w!I+1{)D@3VZG^G~>DICWY(GzM#vt9NmA zJr^y*>wNQ!YTmChI4xRgT+T#5e&eS5$$^$l4VI4}D#|nD(GvvqA~hA`u|sXv>$?uI z?)gol+P`JbF-QLKkZlp`rto{C53|9Lmfv|k)@Nlq#fxuEeMP{lVEimyqP-W11}8&J z4mk)fQ|yP?G4Id;QA{rZuxZ4gnfST5IU`efSEffVwFWvMvv@D&MQ=h5IVcF7aK*L3 z;mVdDOM~%8l8@XVz|_6Vg7Ah{4d2pCh8%s9ko1z0g=MC@=!x7i0ku0~-n2$JvNz02gR06S) z=S+9=6rD!ed=nOdKIVnt ztcFQsI@Lf(2Hp)0G;=4`*(P@BUWJSc7-l^X=kHR$2tAq{2L1GL90+b{qbXdkiKQ|q z_qQc;Z?g9^a}U>{`}mevYLxiReijEu)gB_>W6ZrzP2|NGNJtX^gA$^YY<*M7sF|x@ zcfXIXjO~sVCuy7$;iy}Nekoxny?bzt7o#faodDV!FDoZ&-ElK-=6cp?_VKrc4PF*o z!dP86DkNH~hkvROfF(oUw|enRc0m=#RiXdr(6@Sj$`l7tZq)0wfvH>#)krnf;cYeh z?rHNn2RoaY5(4ewwa+)Iv;$|dlzv*fWED&wa|{fvxhiejn3E5 zn!klEge42Q>tOcc4wVYXJzkEk*^V+DE8i+1clL%C%=E&8EomFotk;7e zN0vC6&O2YZ8NM%#8KCz$%foMXcsw z{oh;9wOB64;rs4A_uO;$*?V93o7aj2kEkDkKp+BTB?S!-2weB@gM$TpBHDjc3H*iO z`a)R?2l(TQV;%wg8`oJ$&lULo>BA4W^v>G?_>ju&rLLQ%lck%d$wv#2r>7^cjia5b znTfLnuhU1X)IA6_2*dzVR*=*3O4~{I%+#8!zHdPd@(7Jt??`{<@21q^&VOvC9K)6? zrS_ON>+RQ%HfNu{;NVcmmcQL0c>YS$NKH-N28;oR-%Nb(Ogf9R-XW;-9KO1B*-w`g zv^p0bAKn>xTDFm}za!~tSz0}9grfb_vkp)9Q7m4R#CJvu90|N|2Kn%n(SZ04o`LU8 zvzEi6zkx%c0sAHEccm3lXI^pG?;6nQp&DMsoeg(%1iQ0hHQWo+L;Y5O;bgA{3F;7< zVVny%gFs!}gZ$+f4YT@phxj+4ve`X6bVmt`AJz^ho-DO`Lr5t;&(6&F%-7iALcRrM z`ZT(oS;p$d&3mK~gbmj1Rr}SbL-U~9e7C6(1gxD#EJm@_kH^k~c`aP-f;%%Kl#@*L z@rE*~s>D1SEczRPT#siDuk>ApWk7O|rVPfFJOpvI)+RVj3kBbcm@ecvXf#It8qJZ@ z&q*4WZceB1Z#+m7&Ulv&42St)IN}R3wnIW#_m5f;vFX3wn40_eTWdt9T5F7AmC=yg z?j-Wtv2!d9trtl8M*Lm}m#uY@6Wq^~x_|?5J#d-Us%uGE62EWr`1_SQkli$-^{fNo z2$mc%Ldt7mCz7n1GfXKEAA0B@OZ>1buw8|vCdXAT zFcz@_5tZ6@y#D~Y`-ocm(GuRH8GgY+1~oi#9{6RJd|1_6_m|NHoG!>13VRJ_C9UWt zVAvril@bovNnw1I2ZP{t(1<}74_ou!eIS7Q6BsA$In?~u=W|n=#f*V*v z(ve`R66%gtCO5-B1`+Y&bWnp`vJ6^%~K5px9QItx0Y4#v>wd?AdJdF!05+S z)I4Qfi%|sHcRM^U+M2VbXS86yW>cv+L7u}jwR_yhnh?ZX$8?)F>43adi8$V%=f`39 zJy_n?x(teyIik$b)&lu>YUJ0Tw@()M|Hyeka63m5g5)EUuvXgsj(#6M;TLMs%yYd0J7enF6k`F+bhj;Z~2I=%L+&@$Wy zQXLF@RiWH|BBhkfgi1{X%#eZn`!>}A3_~LPg-9?RrZZ}nWHg84Ie_J02@6*&k>JO8 zjy}o($($QND>{kpN3*}0rsS27!J~@F`*o>Y)%?Ey-&?uvktH{num%N#G_**xPDfr*fBvB6F$6)~31pD^ z@B0oSN2~+P$0dw^YYg{AZAetKMz9KNxMdeO554nlY-;^B-n(_J7f?TBGc8e!fj5=x z1~@dhCPjrkQA5Xdm1}n>OfY&@J z))`f#S-1Rg&KoYacQlWEPe>0XSdmXaq+}KY#XuY<0AGIH@{_VDTzf>|B+t-{%Sta0 zxkUJQ1zul_IxF|$ipev5CpRiWRpOWz69p%4ECkHFjY( z?23-_4W}d@q*n?&fcR($OZs1|@)-M;SgD>SU@C>ulF7N<4s?l>ch+&Y>JsJMn4HH9 zy^VxH$RD=vZnD37zO1n1QBl|V{LH0ydIIc8aeR#h4VD)M2nmVQNGO#y2VNC z9>R$4BrQf*n8HQybzj0+H5?*^9tnF8O0@Ufd`^~{3-%Kq;aq2f!DKWU|^BsA|FrX7!R>Pw?XZ4Q%!s7GN^I( zL|qi_uQd9gPBurJG4g8*w$qb9XPJGLx z6bomqpI=wPfUB40>4hL%m?9Q}BJ_!@i6W#knzz1xJMij%h)BhM5ur7f65O9b4!Q3R zagcN}m9s!4!#YW;5%Y8UeJ4l5WWLym$=}6c_k=I#6O6f*YYr}jFg5t+pI`t(xh}e2qDL+Y%9U}a8;uc@1CxBH zUKK}o*ZNL>LFgyJS(J@(+8MfQB@P97DGpSoG%8iUHLIiEXAhPH5DqlWo>NyMydj4V z`@3RH#PpO(?IyD+alrA6E#+G$iAn;wyJRW&Rn3zpDj1zuy!29${)vQCKS-spHfaQ% zB(4;JF$X@p@nAH$5IaYp2^=D=0bOQw$!>?U&U&c9SPKut{(>C{WPf@(apQnrFGGq^Z&*rVOpR1>IGInU%|Fp?5y0} zxM>6}&9a*n>7g#bX5$neTDaB*Wh4?s?)^~a${cUcBXJf zk?x`Q&`A+|{r+b3DB|4`H3Fi`D=}!nL!Bmtd6qVk8`Gprm8!Mf(95FrMldl)n5IysGx`PUl9Lf_n@aL-?k^-!ypcz4p@MVhLf6&qiiTh zNQFLd6~8@EI2uh$2AmjRPe&1IKig48%DBP2zNjhaq?J|;$T;L4# zDTgTB=3u6&qoNby%OWGyw$dK&wJsox7fVeW@kGyvyOkTY>b_}m%Anf z@dplmo##5^hNY$!U|T5=!!}O)!G+xu+G`pw$jdbV#ah$f?QJ792v+wgtMEWWE4hTw zIfA*XEXQLxZG^5yf)TV5N9tJNtATnwI!PYl?c3VorHrw%-2+sKi|^7FTcbYfduBZ61+oY0f?iLoYG zkNh69NMMI#iCx6lv>C8m^Ih`}lvs%^V zb3O|l7x7gr`FFT^$fyz{IPiXomelzI9~}vLOrG-CG2H%5RpW9_EMgnNg1 z9TG@X{j_S5GPDbSdV26g2y4K0G`E*u;ty<1ftX9`oxX8krP7irMaqPK;xnnwW+Z4m z`?bq=DU4sYZg7lK`v-bgPal2c0E0M`HqlKkkEf0d4TnjND6@iAd_f4>5r!@fl#m-Ru|A# zb&B-%TRFXAguHx`ej)^CeIfO((cCWKCl?+cBgW@ck=R)Pk@Ora`mMZQ4|C0T}*NlxQdHRZ~@CzzKLke61X9Z9Pgay{9fxcXj40KN* z03T5vET!I-f-l~*dVD1}qoHu6Hz$~5LK;j2dkCSw2{(X3<}3bpBqWpuyhrJYQ9NoE z*!}d`Y>@DDLU0N1h{J}a+7hSTnLO|@gNSp<4`n36hht2+bOmyHw)O%ZIMdpdt;lX?_?|N?F02&lTV;$bl`yo zP|)6x8cs*}^KJLJxe>5ZqY8$}9QOs3%0o!AVf8(YVQiH>k59&U6DZ@2&LG}zYmo>R zq1m5$Axqc=YX2g@&x@xE>qDA19`J_?g3ei)v>)*th>#NYXUX?aq+F$j4%CM=4p7y~N?n+Mk~e@-JOu zX3=8u@BqlAHy2jANHvtaj6PH7lj@(|>3EhqRXAJ$!dpKRMf6JL>^Vv>&_&jr0$|5sL{#bJ7MKKG$9XB&!O5i8bYNsD-T+`N;zLseYsX3du|01LICH4%XG%It)AESABjeY+d)4Vv! zj|fTzU5SStJa#O++b`a^Wpf~VSK+oN@ylD$;E{1ymp+U%I-|`S1d53^xO701N@-Mo z+U}Z)eAji$)_9h@#cAb~3U7ZKzfXAvG5s^=GU5xt5jYQREmLZ7z2Y#q=QcgF{E0nl zwJhl4n(>l?UOqQKM-oliV>K;Xv_td!f?I`%-cGNQCdhGQG55S-Q9l0vxA)k3oR=`h zpb|gS=eyu_5l4{o)~@2c_r1OFF-=022C=MO{ zGwp9=aq)A})bv$l0cnLTIqYKxkjJjS1Ih-)_b94M%DPa(T-X|~!?e^jB9T)S>t5?r zr0e6{(YOG}awNITL^${~Ss_XUq``wbRP>cl=Fl&{LA#cpC66z`nTX7Uj#$fBZVh zo;c`ZHe%M|w|a}dJgxjKGOAQ^Z*jm;{7fHIvbC3Tw(mZq>)yxrGvB(eebEw@v3+aO zvh{Bpk+TYnw*M&cT}Sd*V&jl`&0n|suDVl(6o*)IpIBIW>hJg`MD^6~I*Z__ZoW+q zEVOIEQIzQ8Vi1&XaF!WqyOU8W+*fK~pD@Q-!W&R)DyWJFWc~2oamZQOx`omNg|Z=~U-IqsAM$CpSa5Kx?Kb}PVG6o3h;Sts*F*HKfX}& zC(2{8lF+lT`2#hjFUCeHCoC=`qivFEK(XkCmh2WyeA$n-QdE*?(ecbOhh1z$JqBbf z8SzT(y^vVx0rGvl<=WMVz-o9e@)#}>vfbzavRfY z8%rj*klEksY@6=;=4(nZk(wXMjB$P{rTWG>6R>g_o)vkvJ6JKLDCoQYKzR$+W+A@0 z6B*m>yxD-RFfk94*}E_#y}M_rIDT2L47jQJ;DZNUxgX7ks82mBy^wYK&fp|vj<>$} zHbaG%45?339-E5x)(DOTK#hb>thVX3pX%^J{@FY_WCiV`_K7&5+$3vt+O{vWpi(}S zQv*%`|CXOhOAcrGAgFu7IZz=rZ|%Yu@O83V3;M!7=JcWSvnS>cj~D%YDIZ-f&BGuc zLQ)(R2Khw&Z@UlG+^QynHHsfW09$xy`l5cLGhvm8Nktma;5TL1Sc|!B4F;9A#(Ul1 zmk@eoox&|cRyCBOQx}FfQ3zV68e7xchFN9r3qzH~4HbGqD< zwKQE)2b8n_`#?45+!yLv-YXF|w*}in3IugGkTWZbqF08PE93R^_EKhaS8b(L=c&>7 zk&)-mXw8#@qu6+;Dip>VQ<#tk-+Nl!UZ3mCuYc8Da?%JjGljnzH5y@D7;4oSMxM-4 zWIKA>0;o$(Y~WQ1H6>^SWIec8LIX)S4|l`C?e=R?W)S^j`6J1d9u%@t$o`x@@fBMA z$KMTo81LWgU910deEz;PGX^;HgO*T?)kL}yJ_jwU%G~}~Nyge~by0iFccVmAL>2Fsg2uPR|9Vu%V*dd_&m zdtW#!4Nbw;pj*m|x1RCcEz(Nq1FfY;BJYdd{;TeS)2Kw^s@ql*T;)wLFG%dgE#o?g z?G^Yn1*tON=Q4DrgK}aXxg1puNv-eTss#U)=& z3o_S*K+nlf^|}$dq+K2&9GjWC(4{3;pI?3@FP}&W0~9N+x%a@fE0|WN&TyYf2dWpS z)yrR=6Xn?+2&MDvDbpdBdd;$RDZjjeAAs3fxMu;jJhU-G9wlJ9F>OhpGjxkveW*EP ziE{L^#c*07?Uv6gou`Wy51o%Xj?UgB(6)KtS0&D?1;=aIm-%VC5|7ok z&e+;v*aN7f2F~g|$J+;u^hlz|%$(QP|KO-y=wnL&Jnxmf{53?0-t<@dnGIM^D>&<= zezDHYEgO|}dX;(abMo*B%xP{hm^$T(nwy`&6e{D>(6`szed)-)tNckULRibPTG5NAATrE(lh0*2B9r?$sPIUHBDVY&^Ij+E z&l*|i-1MjOM>slZ-d)}3JFt}kOJD(T96F}YEFU=uN=Yx{Ovvg5=JHIhKSefAk8-(( zPtjC9p_PgsJ67B`zFN~ulJRL+Q-cziP!S(!G5_BV z*$ON~zK22x_eq)64)%%Bo7?691esJF5|1!k&EVq#g;$P&z+cg)%qk8TWq1rJ!d=G< z+>nKjy9qp@f~$9TWX+mx=^Z_ggFHb)^T#m=>er+(t`)@Yppno z^gNBIlq&`P<%dU`Za5jz#GZPAdKrVwcE_EhJ`Oue3ESU`w{r8a4zNnPw|;p`mOJ}g zPAmV)<7U8j9?E&yVfzoh@Xhk$mvN-b|a5W39r`sbDr;`86k>vNZiBWTv%BZ=EQ zcoBl-Ec0KsF&W!mnswXTNADa?;4igK@(~aah=MPyS3QtcMHvmV-rbXLDP&s*=yvCu zT_3PXWTn)L2phazF6q9US2i^DS9qX% zgDPlxor#PO8I@Syn(x->qv3(sJO5{0!9A0Q=_+e0S$!k43Y_+!QJJGfG1gBErYn)- zQI@Z%)2(7VwVao*88yNeWL#Ic4kl>*v2=nVV^<1-t#~i5PY^}zbp>;iMijC_Z8WuO z^?SM5AJC5L0SrG~0ZK+x@$lmHYNQ-^XMm_a(CB1)q3Z-U-CN#sfoZks7N-Qi7$Zv< zp96<<{e)59>0U~mS16sXcp<%_qeG6KO?V(w6e59oo^9~|p_kDc91 zA(IiJ&cd(ednd8^XSNXDHRq|^`x0jidZ;px^;$PKpoUi?i8m=)u9VcN}WDv7L&vd%u~^52UO$h$5Lhhf{L(p zG0L`Te!ZqmAsc;2mPqI=m$S)<_^zP^THN#q$-0Cf0OI8OJG{yQp6z)WKhpL1$WY>wjz-SrV1LjBRyQzitoNpb7rh z7wLJ_skBVDl!|X$=@+NmR{pvVIyRd+R&7=`Tqp_6@;ezw9?I_W17_GvSc0W1@^P{i zG=stLt_~{WbyDNzGVRP(G{yDB1ifezXiB~YP&?vteZV;0<_fnPJBRLJ017nkauG)5!0Mg zz0KY{+k--Hln^(jnwQR_w$2lwA?UQke;!y?bX~oZ^4o-hlpClJg+_mJaEq<+;oH|!Tkg#cJ+7AHT!QrLS>!6;M;GJwJmwD z1hfje-=}S*CyV&1@?5|t8>OE_cwJp&hd2_rzslAoS%1}Pf0oh z-nf;Y^05pKF7xjJY*~AJK89>bMghd|@D_w`g z+dhnG{h{|4?1XOd4hw2;D$kQQFSD5adXAfK^lwCFJBGpFv0|O%llfU=DxlVyV{TyL z05KL`Yx(*tn`*bx1TYe)w)dm?i@9u#Zt`S7-gSLKVJ{Mn#yqN>4;!hr0JF`7?gD#k z!jFme*0k=Dd&mSK0K}Ah>>;MfeA-nbi}B=73#Yk&Tqvi%&r3&N-B>A*rhaip9~kiD zn{Jk^j-p=RT?&zP2~@0r7nnV%#M4mus7w`Zcv}2;NoWN~UD9g3j#Cx;UjL96@ocS| z2KzQVS(1))x-)K$1Mdxr-(&V4+3R1AoK}8?)Q}X8pp6laNh8@)(<(q{dl_YJGuai6 z-oN5goy4xfF(BOYPN}+Uh#RfB3Q(*Ec!S^^m;D`}4!@I~Klretgi)xt`n|}`ErY#- zr98(CQT}HCsdeu~9>xTRT+bOC|EBWVeQeeBUE@b!hb$X?MSK2cNJr`~03U2K>!-hg zJX|H~F)Y9WQt#%gxf$|?XunVeTwC4H&DkYf9)~xB+v@|js~`s3NSTYh|A#{ zpydUz8J-LpGIFH8-y~F&+u^Mb1R!Yr(O1cEiYd=m$A_gaG$@*k7@_SuQ)9iaQ}=fh17*K8lDPSfJG=3USsXNkjy}F>~jKg zVgF!uHbNS$RWHl$)oQFRp5-a}mr8KLru$*QyhP3QsCoKVMgwBBfPH^D=tUD6z{M+t z?+{eLAjhedw|>tCK8reAgtR>lE5IzfSU3(azM4%XewPl7h1JtkBkXljW!H0;Tz~6F zdLFPubh%<9KY#81R>__D5zad1@kA1PSH0Z=7rF&NtZ441<^S9^>CNA-J#;1W(L-6> zftx{xs$mNBrEAI}o(2IE_ryPjAPea&&*Snn^1)s1B@C=4UjT@1*hr=6dFoAH2&;U{Bj}>wS)95I+JUevzvOQNyP8#5WE6~C@^^~cXSN6Ue^Bw|vk-8G&>xUA;<48AXs zTGD*NjgZ_d#V}wK<^$XX4C7=?L3%7~c|&ep1(p6SjfeVP4nOOk<1`m#~bbj7^MxRdBcNgmY{v-fQKW<&O2yTQvo7F=Dqg zX-IW0hl~yyr>V{f5 zumIiSohS3Wn)cU|?QMI)&P#WL=LMl2M()g(@?F69rnBsZM1KDea<%~IDpY9Zlck|1 zml@5ic!?D_xlAw@cz3Y!VR2cqxdWe`bPt*J$IU93?*Kxa{uqN0|+>f5? zioh4&OTJg^Y07p44o}nRTk=xgFx_kecu0Q%jxtz|1Aj_;i-!Qc}E^pJb(QT5M~&7L15{C-bGdQ?S8n<5JYuv!1ukWm`S_N0(m`}5!aUJK@?PFa8v%3e-KzwEhQAep9b|(mL zrP=ZjLj#?7HxJ(W_+XRuwZ30Qi~U?f{Il_aZL_VkY!PrB!Pg@Aq?ev7RNs^vm$^j* zCB8bu2s!gYe}eANp>x8VRrvCHO+T6?_ZxY@)vIl5Al zDW*`t-jK2eWQHQ(_jU(%B>Udm+pp3A>xvzs z%hy!FY*`0n@2vJQ8PqPVGX_ha*BK8v{@t__J~oCONP@>LLgyXGRI3EJf$k3-kYl|U znbMs5g-6nD4?XB{{Rv8x=3W&q(wO`sa)wO-gt=! zE^!0TstE)){P*#jNHN;_rkBJvyMCY5&6!A`B8RxXySx}lOhbArzN)nvz>ieI*qWt> znkqZCxNVRe{Fd=_kZ~KIk-I$KKG9vZa_)-jGr$|FTvDMN=6mnddmDu7@*Ho5p7cF= zzkAz>GU`j#*Nhi!#j^(OEf_m7dw8R{%w)IH)S2S6(=c4%J9JPrkzYat&4k`&@!BQAIRDV%ou+GxbE=fY}#QhsNid-6f7 zqe^{`^EZ|QfVH#S`^xqU2~`Dj)ZTkC2ue|*J>6O`)pN2S|Jd;w=itxF_zdyhf=b+# zX1(xb#ny3e8sXLBHD-1Tz+<>|YN}F@!L=0&*b&edsy31t@cE>rYjJ#t#gtEvKf>1yO8s>NDU$V+)kAXdxKv@ zolS`*`lSU`m-JYXHL*Z*`s^Q;e_GIOf=Rh<#W~Y1dc-C6)=8w1cKU0a^AY+Bh~@^} z>x3W5@BSzR_c@LDi*Rt@l}+QdGYF6WS%h2y?^142vn8dx|0$6RS;be^%cbwzIP^)wYO7#t}mNw$AAv_KQy0R zI;9|ku>nKRcR+qPXKPnTa{Zt7tHO+|XK7^o7ya&MzCjG}fuZK} zCF8WsgvY;a9?6fIgY2~^RvP}Ph+grAG?|=DIj_`8+2BBxzJI?*(jyLjZ3KCo!8=v-%q{>!{8EFZm z8$b(zk=HN(X(X6%36&Eidnqvl7AOb@`$8J|!vGHg$1_{;UVqZhbmw!Jt?_b-GhWhx zL|Q#s*SBm#{^4VX!MIzcKSiJI2cWh9M=W}~R*wNFwk%Nk<_%yX2I>&ibhM%GjZC&8 zD-F!-whQ04{JMIuZ*z{NYfIbu(WBD{m+dM%kx4_twF$?%ZueX{r*Tt!S`}@qh{}3n& zKB70)2P{nTQdl2E9p(fTzc)F=&DiJ%;^4a@%t1W?xwUHrz zlP6u0KEMrw#J~$I9A1-K2JQa~trYZRanzEl4*ob?(X)n&n~CgE3dpp}o^8!}qcTDh z0DsgQK=aDq&5F|AH)cs8P8@l9#Yh>8o!!rOxvMvn%enus$msZn-I8t*?PxYWw& zW&Wq%2}G$~C)M0#-R9lyaS0sVHy_vHe%xnEaKr6))9dM4?-omau)6vIaI`tW9C!dP zUhoO(DuA!F*%1a%wyLc6D${p;!^B}3JYm`OMdmx_JXIr;k+B+RjzyQ!YYK`V6=~vm z$&lCR@g4BDv`{+yveKd$9af9)L@M*@K$o0(Df8xw;vZMv*<@SsS(9Dta6WM$mCoR+ zCl2ng0ksb&N%^SIi;pE>_BIx6Vjn$N(2WL@3qyS#tSIs0cBNw=X~Vi%_jHAPlN_Dc ziolou5sfZdYf7~x*Fu8NzYb@H&a)=uKA!itS;am22Cd|>BCwV^zo4Y4{RH?__JsHm zing$nTNaP(3cMP;b&|+-TuBN#{7cK=Ln9tPn@AYHY;+S#c`M;0C!>+9^=6ugUK_Z{ z0-7cGcDjlk>Y`a)SjcUBHq#Y+$BcT-G+RCb0iml~IvJ+sBs6d{l&X&<%TF(5FMHj0 zG70g&I%7J!mKK2Yrjup>B~XUuF|FNiKu!P=f8s63s|Y+v7?R{a z+zqsM=8^}9M8sVKE@fRILIpc954%aR_1j{py1$Qh<(87Zl+OTjjZ(BijLnQy>Fw>4 z(4Hy&rPjX(Gx?{D#C+AxKEA8?;~p>j(Waof0$%moWt}9BEmW;b^{M7Rly|KPjM(4W z>Jn9a8qN7beLI7_X{dt|#9lpUl%3&TQuS7kSBif3Cx-)>Uv}zB1Gl>F+4=)eT!eHc z*Il5iRNB-46LGf0I__8c&mC#LVFq&6Wg-w1&hDryO;8o+uP%G+$Wj{COU$=Y^vkf- zFfwiy+Z4Byc2FB8+jJA*snc_b2kEy4b3MGRj&W3SJEy)y=G}7qRU1tmZ?nwDzX%YN zW1)mdCZbd!{!Nzs8O5^w8-#A$wFiEcx-P`4`pPiABaNTN)4ZK7&=kwCZc*4w_)Jb) z%7=`Y57RRS>a=BbSR*{tu@wZ!*;beO@oyjTT~qd5&pIB z#Kq+|<=j1jg^IU@(l*C@OlQ5`gZ<7?7)vnAf@_OfIJ{zR2$XsP|BD%QbQj&ZSQ=R@SLJC)u!HhTUHbd6?NSzDs6q4olPID|D>DM}Z2 zN7r;bMKm&#8NH?=dUjK!6Dqd_JBe2XWV`(V%cOI;rNu5a# zGFJh6)7u2b%#b^0U}y&WKFHi?iru1XefmzYL!}kJC9C)e$lW(UvJS z|AF5Ifrz0}C)6Zr9mP(^p=a1~!zX?Q$@dC6Knu<)K)Vchf$;h6=TfgxU2H)o6V;O83a$+w=DoY6z6Xf@RpsvM z5)sl<>TN3f`)T7!qS;UV@Zy`I^iW8~hGQjxx(eKZZc!F0>_b+#`+a)_&%)`O`Sx%t z&(rcNF3{`VMeT}%U@fTh%H|a#LDbgiTu%OBi$!bKovE<`dFZosyWEP64%_oPoHp(FmJ3mMK z=b99&2hK|&zJkGt;J?wG5oD@4bwvY(n-i${*U3@pgiumvzT;@JHxwY^p=8*IvQq(}`lDSFF``fG z6$3Bg`C;9c4oM2c)19PAa@w$={6MEwBWSmpVJyC;|@G5#S&U#+Iw5^o!{h^IIxlk zR&^Zh!*}nHgW0ldIF{P^<_Xpp&VXI@eJWI*qX(iK)>=+u{uj zbw8$MYEz5dietUddpeUgkb91l=7?EX_v=-(2c4uXQ$3pM^gt}l8)&L6-<%B#vHe$< ze*suFm)$`U!1JdsjQu5$S#oZ^ak>b4zz|&r=5ysXCGu=!OQbZ&roOVwXFRN|Q=qA< zi7jl#H`YBzWl1^Mjno0VRBEH?W=?v3?^_{zxTj!2)YvIU8V&`be5`d;*ryT?Y6l$0 zLX~Y^Sb7o{&*wcLI=8R;GV4ct@W40nRU;RbS}ci=$>1bw)Y5r3c1f-4@zPPMRYB;^ z^><(C*P55jn`>VFFNrmRUEWFfX@ocHR1Xan*qvK4ph6?*$o=Yi7X%a86UDZG9DWD8 zayPP(VR2v@yfKov6x}kEcGwKZ-!t&!R%Pjy9bqk32<$f5rqOsdHiD^E6og7a(oNqs z08WLU{b&a_cGvjc3hve#z2+LzXq$N7L)oe`ERv^`0r;5hTno5hYUryfhbM+jdTIu^ z8#F3U`h|GW4kDG!73sy{{@?dj9S^&#ugeV6=>u_<5nZfPt!>69E6iA%bVYfh2{yF89g zsG%TeJKKI`@l13Nd?3K!$<36&LaJHON&15xO!lQ=^=Hic-U)oTkn`iUXJcn;?L@h- z6j>BpKmilXHGOA@1Q8B{HAJLfYFO0 z^OBn!&f4|LwCE&ZxXRyoK)lpR-e+BF7gzXI7XAWrwzeOA#pt)dx&gGb=l@K}R09dt zlkhJK>U8=TrTkyYU>O3J|Aqzk+M0NPO9)+FBG#K~$y)`0;)$h~PH!@G0Cb04Z{eBy z?Dq%6fij)tUl8FUq}h})__3jELus%SF>|Ae{uiVcD-p5kHoVDJ+>_%(VlRn`1f&Q{ zr!wALzmd;42JaAZSdO;u3dkLn=Y9$0tQgJNNf7`pS`^1;oS@t3_}nki>5mBPSPoVE zH!TzGb35-pELSEC%b9XFsh-dAh_lD$89P>4@aliD^JDFeCBEzVn)?A?7}wCp*y6JZcrMeQ$dFyY$ySvWA`+euE@5h-xti^(7$8+y{-*H{n=>8sB#a?dz^u<_? z67rNc?02kW8-jr+Zo9(SD45f?8_HhZNn6>yrGpu&6Ef`M zfD)!!l+sPo5aqSE0$`=Obth^|MNOIkAGek@Os=nuV`FbQ`sHVt1vGhRrHN0DrQD(< z18N1JC%47=bwYZsmKLH@vfLA;DqdD5)xcNvyWhpRGDFWewEEnXNNm-^OZ8qWtiHe+ z&j?0IQG3P-G8kUm*|XC1>ILwQT&BmiU>ylc=Qv#7`amzsXEP8`$?>!Zf;VzIj0E?cL!tJ`LX|y0uhiY4G z*UGuunzAUI;kUQTsQjV`h2Bf^4}yi+x&#?m{JSg)^%Cm=>kb_)T=fw?=3Kb2Ely71 zhx|uOhkM2%*e8`4H)tnpS~X=FjnEajK$~8ZqZT!KWP(f6Zh-dDuuK9lS3F5pAc#Pb zPR__Fb;=_zA1ur_NO;J9e++?zT|4Q2{Iih!lOYDy!d_0b6n@Fvuu&jQMphfBt~^X8 zFmS>E3eV7ukE`-8d)_y`3MLr-ID2igO?qwkv@9!C3{<*l&EWRV?~n_xx>tXA+*;+E zC0Sy_3@d8(cL3}rx@ck*=sRVF{f$xPBwLe8{8UZA{nHP^dt7&dPwz*yit?!-LnzuF z#-UQj^Joge4^j@!w6fqY;;1ltxSymokY+@SQLRWhOYZBGs+s>a?cz{Mxb5_4->vnk z53!wfhvlm{u+h#-aH7jaU^ku#bS^g2)HB_LjLRVKb(@!xl3VM3Xw5|DZM4O~G z3(MbN^DbOo7?ylenRzojL|;Sf#zu(WO@zH$DxFXjR#l#jmLGk1ZJVRm<=m*k?f%9` z1w~@krH#)~?aR!jx)yNTQONByZsCYI_HDNr(P+9%l>~Twox0NldE;=Nnlh}!l-VAV zF4mrZ8$vlGHdyuAS+BBV_)e-ig9CSi;Xi*+Y7-k*)VP}K(x98B^-rwd+T32l6A{Gr zd*ZKO8usPB4-UdJ^MWCvfGRf%6HySLR}$;YxjknnG}jwn%x*o??s9Tf2)dj1T+j&0 zsZcrsszBi_2xX-q+tBYc6P*+cr{S?~ZF1WH$j=q7Fd~X0`dArRJlz?_XPlC`{7I@| zapANw3A#JBFMa2B6U}dXo71DKM)=MO_QIEJ*kP2@sBuv1;b)(=d~}C0X+&7cgRdp|j0IHDp?xPX+QO&G9M_ zuKN*C4O>vprw_o5``BT?fuWQz#FMZq2M|mMGb*bh8L?x3>6h`C`RG}fc_6>;qIRnM zS0HtAj)Bq&Zf84MJ95WUaP-3v8oG=dnL0(VUoiH@zqiiW!d!akUeJCj{_6KXp=qT) zlf!uRTMW?2vF+oIox^C%2hV}vF1R#!pvt5@ghFw9z@|SsC(W_ajdyr3VLcWR+(Y7g zMVctyocWIePm*!Y7vI1ByD-~(zmKyKj(j9u+Wsn$B#Al5g@OpPOp~0*?UbHizKre| z5qp+87d!yGd9=8h-q+x;@Q_Va}=(?Ur{cVAOD7|Ty%aW(kn!_9%yHK zU0oS1@EmcboKdG>9J-f;R~ozV)$6w#$x1fhHlytHuB|wwCu4?Dw8JEuIdz95MtgW% zC&I7=@-pf^z1~7HLWq$_%Ju+NjpUipe+<(o2YMr)p=ss9u!^nD zv3F)L*C$w4H0Wy5tLmj}q|Fqt^DlOEg`j#u_dlG`8_z^c<|J%tPOLB%iufweUZ5VK z0bXESdzaF~;LUEif8ltI)`qZ_)enWw>lP(!iZami-D&&Kt2d9eARE4XFpO*>(_>gd zkde6hbY+C0FVbHXM)=1ZlRPMtbUSfqGNJD67a~y0s;m;m=5Y+>gzBs>JZvqR;w5;c z9tVQgE7R#fX^&o7fXtqRuW&)be_Banv~;47xvcKui6{G=m$=<^+h+WoxBguf$cU;L z)xRPSSeXedA@Yk0H!6a2Uyo1QUvJy6I?0B9#Yo~8n34G1%CrDQ;VwwUSVsE9NGN1! zBa}heGk7E}Im0}iKNwP9nPGjEH(`FE^lqGBS$9@QyzSpu8`nvc7~XG#=P4t+l<;Z* zdD6!g!dj4?`gJxu0AZ)|%&RvZz_ezGe(;Xni=&UqxEtz|6zHPo-F@vi=~=}siUwTs z(H5*g>FZGBFe6~v=+;f9I(Fkl0i?pGH&w8djhdn zw87mmJ8pED(4KwL=AA+m^87abx|2pmt`tmYV)#-ZpDQq;NuL&ZRxU8vodK7iKal6?9)pq59vqkzlt~U9s;y_ZHIO zYLZ^A`M(Z&vycf@K-fe}Pevn@S~|F=1b|0!PJSETC4?%jROO-V-u3ehJR!6XbvU?Y zq?reuVGN8FKBKz8SYul?Qi}K?02A{V2bK!JR78NZMyq-S7pNWm>-2T(j4^792mD{0 zRT3!6{;7B5c_|HTJayv-5#>H!C;q3jmm8V%5sJLu(sUmFtgj#n@9HJK@*ZIu6e9mP>T&`P&l5&klvwFv z3Vh#|zJQk!?fT~6v_CkENohe&1YoVYt)nW^pjMZ;ws`tB+G;jGiEQaaf%H0AUqaR9 zR{0{2VC9?OOciMMq|vyfW_l3H=Xf*c=eqE?SmjnoRJ71ui)GNv6Z8=Q5=ly&MTIF3 zAc9?KCYg?#B;t}Olh`dbg?#e3@0@2f9?%!jPh zxN3e3C}l`t%XKP&?eRf~Y&@tl>jP0MB*z0h0G@u`z@(FDiR>=oex7YHrn2PG&^F%WidJzp)7hn4=5rPl}_LXH(w$Yr)M-!U1c)( z-7fB~QkgqjVokd3*9pVn%@p_Q5q;{sS6Zk=Gu$f5=us~X@OmD8`VDvRxj}Swe+;m+ zB+Qai&)yVZbta-Bcqjy0URMmHrWAMzUuNV8e2QYL{2yFb-hpLlZW$27m2vL;ldG@8 z-Zi-bA=S@TB0VOw&hs;JXso!;AkiU~z#D1x*8<3@s2P|NYkz;X#RDsP32Gm+9?g$A zTU2MDxsc%v3v6T9;BtAq5!bAwu;DT;z5Pgz8s-!8{ywI+7 zy2j8K--RYH4?jI;slQ!@Ift zj$puWg3z>nfvpVid(J9c_kOp1kGcsDB5Ku&|8Jl^8ogYxPWH;~WuBQDEM)R9$;u!h zmHIcHNvMFsJsN^V|L>Y+IK}i@EK0^=>t2G}P^^bJ2Z%n?q$3GI=vM*AN z1(^j_g6=?#LB?hS@XpSAKpV%h?DPKopWfu3wpYcIJd`zbMwQDeXe)PRR>aov>cp5g zeufVNK6)#LkCR$p=*Zh?)mk%8sde$z9kB4;YH5pFdH{e4`+QWN22`lREWR2Lja5h6 z5nXc%awd^nKo5}jdu&~FS#*$q>N~(a2Lyt$o${VbyH$y@$O!~VetU(PO7IKo$q>H5 z_(AR5Nf@DT(d>7AWowaoT_vIxAE4{Hm4X2BUKU(OIipIN(*0>070;Alc}YUX#7f$v z;b2bN(B!hdO(Fndre)naAl(n$>q!Gp*1F}fmUs$=#Y{&bixw=(YBVQN_Mt2cVb4%i+OYTH<(?_gM|HD;~1nZ!N+zV_V36s9E= zE#TSYimB`aN-6ooA`A>vS9h*Wy)xd-Q}>$SyRGA_6RByur}N^AuwN`yH0EnE&YuD1 zAPt+it)QPUIgo7FpQf5YM@UlDOM!I& zqU*a!bV#jgxx)o|Ia#Lz3Y)h>)WM0PDj{-22V$@L?W_MA{<5N^97=w$j&4n?1>^qn zk~lJCx#3Jl(f&((SVU|?`@=VVRvElRw7W_BR2o;oD)FvAaJ1IFIE5h|%?@a0wEZCo zZXRw+t$HbXuSxlc4}MT5Y1pLGOvmh$bj>Isc_jV>bkl%NExw)bmO;^Etc2%8aJC`| zAYDQvZrMCE=Xg0}Vc#T{BB1E%DLN8&=~CFZ6$bdqF5~o&bZ2YNNv1eQG+3bm%0o1% zxVph_WB>7Z#uO29un)+xFZK*R{HywMdeS4@x@# z4?=|Pymy8-f>>Dj?^D0EvH;giJDr8=T}&ZFOsN= zg4530{_^FGPw3Q5n*}8~Lt@LJF3*<3C|p6i%{s^Y zrC}l1(w%aV2IDwbK2IEou2E(2q`^(y+w3s-JK#q%_O zBjop0!L!{}E$Zhej5$}%cs=j5rc`u&j|Bq+*X`YWR6&o+cO{x$-OHAlBc?F$gfBV+ ziJJbLrtf^Ub!4Tw;@5PpXl_pn6|u!wH-Ddv4CmEyXT3-8JJyDj7MZ4b#O_5{VxM!j zl{VWU78SvA|ALD6j7aF?zCmd09I|E+oO&0nY6>+pSSqd`sF9J2N;$cUF2-kwk8 z{F+cy2@}pK>_5~AgOwSa_Lt7>z`AJtT&jfq%$Vz+W>IFZS>{p%UaL@C!{1Q5>2g(X zG2_XAXW1)NM->VE=4_?0zIY`GB?h!Emxo=|{5iCKg8@Qyo&~Zdu_&r|O!myWwYK+$ zN!)P-mI@A-O4f*jFw)}1Di?h{@ia`|=xRv-z`MfIwf(iE>7KZESXDLBJWn^-879Z#B?M1 zu5P^Z(W?JQ7;?I0D7c(*E%_p9L+#(8S9d}P_ikHhk)B&mIW%nb5%#@{kSE!%6vs>H<1kx}NFckGys(Kta*7O{< z>E(NI;sH+Pd5MH~$Ka)hGqF4Ugy5f~0>-8a2xoq{0Qz350ybCni;*}&nZxb(IrULkoKZig zD~x6>*=cqH)&yT)c4g?=JF3GFSzVqN>_En>e=xRDZW*~+cRQPnwi7Bo71c7`6T$j* zxZc8Tw%ojz)y32F(6G1~Gd*%nguQF+Ke8GN2zOHb-yc2lfM&{N!|Be2y!&cbv^*CjYK!)2p8hl2DismWFHb^VI*<%CKyDf#!w zrc}N)Oj7R1T9J&(TWSSGg+6v=_hm3Kq7dPa-Sd5dZ$Q>K2|D7nlmP^2{F*z2%8x|W z+xQdS$#(@z_kK1?dqb#%3sxdIp+vw*BDdL}BIYMk8(lHh`gd!oI(eU8?4|yCzz#+! zN0 z_tKn<-IW8-O7lC?HD1Uw9O+spU=k1ry;Jz7+uk8ikgo1{@aYl!^LaZQ4iQe1em?gA zncY$`9Vv?#hBvY!q_J2A=yjaeRNG+P>~;%>JW4af61-Nuc_V@KhpYxmRGVdQ%+x!h zvI!`Q8K*w(U4+jvp9_<(Q!m#0t?Op0wz|B(8LsK_#pz7xJls--dZud@G1shMInEC{Bc&iTJq|0c6I3#?Yn%SA$%ZysX1v` zP>Gy9t>;!Xzl|-KXtqTOs-X8a5kf+uPqS)|~Oe8)GcHOV*DEDmj{;-_FE zp48f1Zn(e`Q9KN*zxgJu}R9Oyhe#&{z|VZ@B)AtjzEA{^oHt1sz>P#y_azeYB(ikrjLDGRq>_yMSJhCGUCo8jLjY z);AU%{elmybCJBws$6cHq}4MB(Tn_Fl(8rI z`KilcGWI%}G*g{CnVCLGRgk|Fe-D&AI)_tL0N2#915j%ZpYg z{>Z>;5ss3M7m(Gf1B5{qyQodC+~%0S;~wQ{U8LAA`GE$|*NZ(_=vT>e!8^78<2e8i zSW5uqtBA^|a*w3W`*S|#G#31jze9ygn;uuy9R*H#6r&&B=vK)AgUoqFmc!4D4)H|f zJj1`yCCX}m)%_MduaJKum#aH_h+qh&K9X$imz;T5+0DF>H#0angNZ9`kcd>J9F$W4 zgc?1>p@KVP0412EIgVN-t`Q|G{4Pba{CtbbX08r9b8z9G+)r7KMBJM@vHG@}`W)iQ z&l$L80X@n(+WwfxkM0x8eQo9tOWGaT@vIiCksv@cB*JWLq)!8^OJta%H|MIyG(NQQ zbC!pk;MYY?HUH=11+rb#M`4DbRYl4m;8)j^oh(gU4VK=Jbt2}i!+h{!-q&%l|yBBg4pKCYpAhYL>#$+{@Q{8~} zSVjquGuA4rm}>j?q~t$RlVK?pT_goP);l0_-Hw*kKNvwB z!d^)jI|IWzh*9}$TTi2O+bP>e1ZF@?Ii4~gd5^I%Hx>6r%Wcs%sua*iRK58!o=|%J z^NR40fw)nbmcU{Bt@W>%eQRVC5RHkpTQje+Xyd-L?_1+O#SpE?)|%BAVuii2I032o z*e}LFX=3B=06-59f@2Eay?G1h+pJ`X(MKQbi2WBHKy!eI=s;;!X3-}9X5R2H0cj)p zF}2XHin)3I;>bUr^dd5Yje!}^rIK546m=0dosAj_Rym$Rj zlHo9&fCQq(9p{Fh566kt5MFSU6k`w~E@@nXFE6u* zu=AuWVlx>5nsRxqmCvEivTd<=W%5@afqF5I<+b?{!(v|U*9VAja;RC7T=a-hUOZ8$ z!fDVIDvKha+UWyxIBg*X@2S{GDVN38}EdtZd0mNuDo7UeB5L85eKI=?O|g8Pbks(W6n2XR`$d z@ebkIB-pLKl(CErTUqf?oT@!QVrMs;3n z5KB5Eu+?H?b@&-R+%fMC*uk8xBZ@K+uASzJ+jf>dm8m<*B^O0F`2cP$!1yNyMvO7slur79V%pg`e}6RLB2zN}*@z8p zFKwNppVS}BF;Y_c9#=-bs-UU=0I1{JPJq#bkS@>Ydonr9Ec&K|+u13*u-AAR&iWTY z&SY2tW&bZ0;Bfz1X|KBDs}!ERGc%1`$JU1A_1MKR&zSr5RuaI3JKM}>RQLJnm22C- zq6kSBWJ!43tFFh~$Z2q~%-zQhVOJEvotXHxyyqId#@4mr5oi! zq#!6V?L|%5L5o zoTVQn_)9xB-hQ(~-Ge<{PN3*xz#4GP;EI0K`b1au4ELwMr7Hm|ZteaR5_6sWxflw; zLLj{Symv6HVEPWSJ&B@v&&SP&5wYJH1DQ7z^KycbA&m?BU96e-9gL-;g@&wp9hex3 zAdtWl0yf{jl6HG`SVEx@0ZxTZKkIn3C-MzXj5pDKMV9&JINgs;McO=1nqxR`xM$z# z_O2urovL|lW0bL78syr5Or&Bdt(yr=hE0iY_s^w4=g$efS98m#zE?|zSXGLw4#vR( zg`c+?IOfu|WQ;O;71P3%Rfzt=3KVP@sCf$W zH+{ZaJ^U4pRrei+h(B+gO1y>j)kD^$-?S%R%;oGnv%#q64g84tSmamDz`3xm{#JFt zN;Fc7mb$0ARs4jR@O-2CmHUaADZD>QKsSqlw{cXy8#n6Wd%{mhA(LQqa-aSxFSrLv z2*zG54+XNWyc+B+rB%N3V*v#tYI)}Kyi!=ao|9Aqi~QE$wVAfW8frHS_lVe3_r+tF zeVf*K`s7A$pS{3s26*LU!3oVBE2tID5SN*`3L8VAgif0ItJ>4|^7Xnc_7gfHRjRSIy~M5CGpemYsBcU3 zp{`doj%ON-O_<+!1PLt(|E`!`PehFRmdyV;jPfR0g?``qaIUj^8$Q2?iy#hv`aI9W zz1=K+DD2HaTLS6)MW(@Bk@r-8pl^N@0IvJqzbe2FihfjXNZ;*k4uxKW$*E&_p_RQpnjFi#E<+9!i)N97kJZ%Im6Rvj`bj2em zP|P|Es2N6@emF~}hyiqk9Ji!qaM)IlQN1}3t{E5{R^7^kPtnG59|{X#0#ChI;)oEt z$A#iRw`;D*B~k2jtOZuq@l&oFgUmMTzYNSjIuWUh+C}JmLG3fGxEZLhwE#z7F5=pz>)zSHPQ$wiMYShCAl?Z9l+#RZNtY(^ zunRV!^Zx~E#RmEKq_sQ@(8>7AB;t+Z!LiDe}0<6yqd)6^3|9OD&idO3cNH^9>1ch_GF_G;nQ^D?H-fwjD_yZ;}yI|%zDn3~v@aIm69={;TC zzKs+lL;A!VwCLF%$B)z4?)Jt;U&dmET0e zY>_{Lq>{H11(M(TBT0GVVhowcV}sm@P@%P7Aw+uyXR}6tGw=IjG?bb~rs+rR%!JyE zI>$oNj5p?rY;OS*gx8m#%`o}AB1Y&{=ezzp|6nSO%a}Dg647qqMD^qOA*B^l*0&Ll zjjv(keJo^gi;T=^o22)CM}Lvp{AT}clNWF^Z@^-t9$2c=-RvYBM4=Q3?;+uz1Al@Y z;900>l)({nOZuhiOB(mbuTuFm^&88ITMVv;XfQ7W6{-i!xWWXJ)!|0vQ309gq-IoJ zd`wgjNJ$AVW9ElGDNp+p*3>nEtUCu6@_xCknWQj?NCF=BBgq^VvP2I2m@@s+X#52G z)_D4+qX#i(!#SDHxVDlrE<|&=qcHGLS;;N+azf;t)dh|={U&!gBINh&C&3nqC5qzX zB<>0X;-af&WhGCUDnZ>Ry&vx~0g{QTpil!^#Him>?kmt^?K3T{5IX#Fyeh3;42)oE zzjngbdViz$o%2T zC)4ZD9N$bzO6nU2rN`(*KH5#G(iIWAT!nvMC!YATKOu_msiw?=Ycb&pwzB_I_ikYH z*1z2?ceX>!&nR2r0S%tqw6r;ohA?q5KSYeZa~&(5c;@X`FE*yugafv)0r_1tR@f%2 z)pg!)C~HrbscOvKVtUF{1}N>{@UBADpYM`W*l2+dCgM)V-K>DVT%eh@KbnSI;C7Su zW;i8W_X+#Wl_NxtcbyG$sNZ=6maYUDMn3QVNZ&ExfRrig4pln;0epZKrGbBb-Yp~A z42I+bae}~2hzZWq!{lJNj2tk5q?7!KL*=UmR*Zt(nhd zB3VjiaQ9!0Q+#Tp_DB)%Tvsr+FWltkcyx0l|gFp{x&PaPLwBWXg-m z%EEwwE#KO;CB4BE(Rpqbm4qT0U@SCL(A)Fq!MkRHTwEb)dG+u~#s|1C10ut&ro zPw+9xJv;$Bm181HzuNWd5@=q1&12;84ou5uNhe>LW%n{+1l^fdK++PbpN>+{c=U1^l&J1(MTZ!7o!tg+&D@2BMRa=^q&M`@$u zGC9bCM0lgQqT6a@&bP2QuB(!jx~uCVyvOKeb0j6Zr!^6j$ErZ7-$N8jyq_yEXRz&@ zEl)&1%e~*J*(i!~lrR*$2jCsIt8}$g+PKgJTK!&(aoupsqNVNMDGNsbsSD7#8NM!B z;jr_rT_zdT2$3I$8>a_|>a%hfg`l zqA5Sj;A(w0-0`sYVdh5^BC!E0%85wKq3=gYg-wHC0@9?wUwWuD)R0!B(3a60E3X;*?UIYG#a$Cr`wB{T{Ji#O@3OuSmnb|XldnsEe!mRn7_c< zL;1X{Az;`$fu~wTS;32)F&9?>6xIJYgk^yDO|HA**H4Y$#Y4sfWc@`759X;(Bos@t ztFEi3AZ$(7f>_|CdW$*rI<|JSE+%3vs=S;A#9okLB9w(IVgR1^iVXW^B2PO{ESaa_ z+lq+!06bql`0X5@@4%+L^Y)U~k~< zktN>PTL-H4*5M4mr``T&vfZHrUg!dXd`m21W);YwweB_q^VC-qgD9g+IK&s&XWuJu ztZ3^1ykh_P>48{ZrVTL84^)&rxT*PsChf;L=jN@}E1w?xTviFIu$Zy3Jhh*fDe+`Y zaA_=${;|Ms15F36?zgql0gI!h<^AC`=|`lmH32{SonZwn2qRO(3jsk^V&OZZJPJQ| z>9Y&w(2$FzV?5HvO_TI>c3s@dR%BNkWb%_^X1y)8LLyE`3c3>^CrU7F1BlZ?OtRBX zY|F=kZ9-B#h0YMn7P(alrPmAAk*ihym?RQ^=p!5~@m`*RNGMN)GTtvFLX<#o|5K*J zLX#-#pbxcMuxQH~MP>>D(OB^{PC%*|BE@eP7+E8D`5#GY#QFzCMg6xytgN5O_Y<&! zIWYREq1eIGf0L#yvh#)9iW(A%7%{BcEy<30=qDZd|0I*8R~4V zvVb1Fw-V9E#)exBbR3yVzvAw=eA3;do%YOJ8GSar7a3WoLEXp1x zL6dJ;ZAYs>wMrI$3mmbJ_U)V9DE)s6*H+M*HG z*)?h2(?bJ%#S2zs?j~4#Gku ze2GY=2Lx0+J~!*fI?YP~?7)gT(PaFt3Z=WfMaO{LFAbV($n$P@gG$X?sCj_j<|-S* z(KF2nf_9#4WnU!NcH3QA$LmS54t$G+B131rxa($<2e#geAy;%p^NWk7zWu!lSK;R} zI0t;gK*y-~&LF%R-~oqbOdPS5vl>-olA*N@MxkN#$BNqi3HC;XBA(Ywn&o;skd&9h zz^3og#o>wf`WA<_<+bJCI<;Ry+C;GCirn<404(e>o#)`5stAI;Z!x1lb{pS?u0<3T z9BA(#JqCV0O+i^FQwA1TR2~Ny+hJ>epfJxo` zHEut(re;kLbuB(;BGMdCo&HnC_gRMBtNL3?IfD+jb9}oDE)$N=!!nNE2ITH#eV7rg z9_xbeT78zSTvj5$oz}FM*4=QMI?sc>Si|Zg+uOlK|LVif;a=flA!F-pX9Qs8hNJwc z9jgz0Zsm^)eXA}8TfbIcUcM0PL;k9guJ?H__){Piyk(2*d#b7JLvlyeKwDOflT8IP zdufYP61m=xT5puTw+nhiQ8efk72OL)w+Tp=)N6F0#88#nXg{sTYK)RlV9AVZ2}>=f zk><{a-sInK;F!(cl^SY;$ayD%!NA%4H#y&mp+MlNER`?Ma(5@7eKCZXisuzZwzV&^(8ct8 z^eg&tHoCmCy)FKS_!WPBTGh)=#J*OrTez`~hS4FGAVw8PHzz|kc~KpI4a^a}rC1zE zw8kS5wp9b9H z*>Sm#<*;~(e(HS&4=t_nzZY}JsN6{SwfYY+67PhmK)C*O+#_x46`(j#WrmcS3CJ%>H3dBz*`&%C$+yo( zDIt``ok}e>qxE;Ko>%(CM}W5q7iN9h$kYC_8!v92H*J{4EZWafFuUk@16E4OI*g3~ zXU7Ks;^`n?%v_2uf%toDlNk#R$$7mqe%jU>s!Jqn=*mhdhL7{Qx2SJHOCPKAj&BTR z#V+)=Hf*S%o4L)X8{BokJL#nb-eT1%zP+r!I;O)bo?&ND-@wjSo+Wpo7eNYNT!J(pzUL>OOu~;)Glj|G{nebvIcE*~in(RzLky zf|o}VCit3napO6Y`U9>7;?vAxqk>j@{BqOdVklJIk;QNfb;i6gQ0+ouzQt}ioGR@)D z51?2UnXqk#LoITf7^rSd%o$VlWeFrY zzR7Czc;oMs?7+^mUVs#G*m?vNH&8$mrxs}R+e=%%zP{{HPk!~PRmAKp&}(sI+{;S`QUhm~K5 z4Ck3BGU;g@TyFLbxc$n!g;V6(1&5rm1Gs8TdRN+fpGWuSqVRU$Xar)py?pl#hm1uQzn~{+YmV$bijbwD898Wz{Cau@G za+I?iJlxQ)37$z=FA&AQJ+3%94;uY)?Qzw(N{CNY5$)0l@mJTqyyiM9zC9dWR6FSCAHOo?Y%-oM9qQ6t`Mr^Q$gLTr^ z|MQD1BAN7F)i+<>v|ji-+Au9`m;*cia*HBv8RU#a9YCU3XwuNr-K_G$|*sqfpYrUwZwniMhQ5M>sNyMlBm zRWN%P*Bu$gM!ROqKs0(J?sIb6+FC6WpUGuB@vme*QzWai>pa=P^1C~nKr$GOVx&8) zT?;Y5gAlUrVM^;?{CiTK2gHmZTF~cRnjH7G&&a6w_TmvTDf?U~g(h9+C$yL~C~r*l zY?vLt>l(Nl#m&VAlUm3fAG-{;whxZ&-$IE)vljEH+w9J-W}}Et>pDvOYUXW4f|B+V z9PlP{E4wV>mlY@>z>>7V*B3s3nz|GS73pV2+)lq6xJpq3pXL?gmGhxgyY=*^Z3yv1ZCUt8OA zGghPE`bB&ti(Hu5A2aQ=q8zQhNJN2wH??iFWdrzdV>8P;>fcBhgNjW;cece#^T!)MG#E^xRuFuwi(ki`Qe9VT6?FUYE10UO zJ)^r|!23y@Qq49{CQU`u`@#HCppz9Ij@JIgf6Kf{ra)N<&M?}a=94^#lCfpoo)Q`L z5uSuPi>e*OgDgP;;-voJiWeqHPl6kW9LkAm=>G%x?Vo`x5DtA8uhtPemNLD?Z5~)u z=r^xQa>gf*8D@s+nDGJL&pFB6#(WLDdh{acq@q&1zmUM|h|umGxa^PseSc5T1$P6A z$d|IX)a%d&qUF9N%~q^EU7!Zh1IHs&%ir)SCrz~Kc1;ogqB_OApgS!hwy3EcV;U^9Nbbq+L1^R3t% zM3v%zgBGw0_5WZEDAtDK_jY0PGW^6)*lJ&h7_Q;3@Vw0d%7KD#W=7g#1JM0H`@1^8 zYTUH6e~kw+}5?WMXA?cTM9kCP@~kl_T+xph+xwyYTZAJY7m{2~|&56Kj|<1Z0GQ zE%x(H(yAr9YUaeS_J-$E(TWTgg$u4Lf9Y8DXEE>vZNBdZiJWb4zk;wK_8TAK}3L{H#{D1NMcKCSa+HNLjAa1a{4~Z-^dTBV3O>k9{g}Pm_Jz8a=V0p@s4*~ zWvpMzJ~gngbG_>OjDo3|56|UaO;g*3cyG@RG)Fe5^x{MI;q4g@l7_c@s-p=VLQuc; z_-{w&ef0wxm;c7%T`R_w4&U7`_PNk4Y}YF>@^ zuzR*LnZ$*2^YFw+n$JQP_0vf*iEiuZWhnyNPx$$--gkZx3qI%CCf;)Xh~_(GyQC&%^gyU@Cz2BTw^?! zUDk{rS7bDe4lT7MB1YM~csiQ=5<0X6p0gTIu1t94z6#U)N>F*ueZ|M^N_^;}Lu6Qk z0Fb}$@&m3r@u;HTAri^UE|LafGKn>R9sHI>yC^Wj;Wa49R7F&m26n*lmTE@ok=A&% zlYGF3blE5Yc4C(q=j+^>cS65VbPWP`PA6pPL(9Jh#at*8E^t)c9SkFNNYy!%=w9VX z>C&128pWz8dbc%ZaBL^Uwv7_sUfDW{U*r_D?i$gVxQ!}FTWUWaQVulQVW2J|yqW_0?LtQ8?0ZN{ zqux!;KXVOjFR`lZa{^nmG$~z5g8rL{3J;AI-d|PM67N1L`PAGUw0aZGry>~m!T(E) zM?~+a3>7-Clh_MFBsk=Kkk;@G>6Gb>@D`e&&Po3+oS6=@Y}Btu3)wG z!>zOK%-<|pn-?=zv~2F5!QN3c{rWKj{6AkQ&2ysZc4bG3Kc%;G$N@CJk z#5$(Xo2d>phw+3H!O)U)jW>eMk_~X?t*7clS>Lbbe<$Mm*A>4m63(taykY%c_Z;nl zJM%ueGC+4A|3?CP*jLon7TC8}+JcO_+WyOzvAo#y3mT)jSMy|afa}i|V!tn-DJP{g0BT5uIg_o@*h#_HR*T zpv(d|mj`KGA%85%U{%vE6|C+26Lom=30|)7DrQO z@ z`@WSmi)WHlDZtX+G_9&sTGt0IP^uRwtgMbdqaN*rSyDnnz+VOL^8Qh3>)4_1Cu47q6&T{Yzc%)O~eD^;4wW?$8 zQGk7x@oC!qX<_Z~uFf4Jn$Ghl+a&)?MdbWL&$Iy18Hx#KsRiXksP_Be*)!Za7Vd!4_Gq+H0z% zxNuGy$O7P2u=(&!#w)2Mp_GndA^#y+>M$XjpQ16h`jru!F~Q{p}6UWT@bFeCi)zSP}`<8LHYJa ziG8jud3#LA!r7WlTmN1)zlB)(A#2qZb=R-*#&Rt~4F(q0Di(G<@lNSpPu&r~+~A~y zv5x;+&Q*G-1D-ZiCb@6{<@ls|9@_BGIQg&0Dav+PozxOp?tEl-&!u+LRnid zYZSkc!Vk(hrGOLJ0j`nk-EfJv@23AILvu1JlyYqC2X9m0$5;9V%ycb+_Aowusd?uu zBuuEZJ$99x+-Z8w0V{f!uwPNpcl zPu-JSSI6bS!L1tzZ05PmnQp|fKuP{E$nZ?< zd7R8A!O*WAnMS9C+GKVgt^k2{97Pl(xvvz-t@)BGF!e&r#d%vEq*X#Lyy`G=fyR0L4byY^^rPGODpAD8C>K&Wt zz-vm1{x|yR(08c}DYzh*Gq1%z)z=a@z`C&m5+bN4H24<8-5wa8;m!8IJ>+|*yG6(>?>g+|dvE2}{$X3(vkKpRkLcF3x053une5jA= z9{Wp)BHE9L$TugQ@r>jUsZu$LHE<*2#7n&qcz}@Q2>-3TuWjM=3;|Zu+b2C=8iIW0 zu=1^W-wGO~UD?+)$sbQhz9e2^t zNrS58Gt;Pk_ZzSO@qCS+L#ISc$y3zp=Ix{ASNK6J6m{fowiprxrwC;CH=Tay^l8Mo zSxbw^-;P>~2|JG6Xd#2T(d4U3|0=*!NtZ6(FII+#VkQ~ zd*(Cs$xix`Ls=}ildvslsYs*~3URGpvtEidOu}j3xO{9`iIPpuY!4uXB*Y9^H5PHD zieM~)(AFb4q^B(+w4U_8g@2%TRxS>oQN*|7=KuKQp?vfsfC4~^M_e6T*q>{IM=+N# zeYnF*>Kvx=MYLx>NK`WzWJRg-fiaCs{Ma#wGox&9l|6G1^6N&Z&ZN<--Vk~d)dLPO zVnXyj&;)o&YXFlz0p)pl94R_7l~JE!dp9O10~cF&!z(uP0Mhp4Mq$j8PvIL?u~q4* zs6O1=4U3o^lP_rD<;Z7#jR;jv6PH_s#_yIs?d#b|fNgf(>#&!WEXse+MZ{l~>W+LG zZ66T7t-vnm+BipFIprj%4v1g>`1y=spFrSHxLnZ&QO9Q98zwrTQ^>K*dZb|C130Hx zYyBqR@9@Z{?vhjUhG_3gchLvDVq~vj=L;Cboi%W>z^5anU}KL=9_ap9osOOe2`3H! zgf)TMJfj0z(JB(R4B_*G%h9j@HDVvYJnX6lR^aFHd4RltJKN7k@-4xAc_;*NRCz?F94}CVEx=% ziqH_8(Q@2;t;#v{d%>NKX^s=OQ|qVGGT6P)8D<7e_;(S?W-nNMzW&kt;$oP z;U98tD^IS1fu?BRs(#wtnZc%K0Xh3M#nmdf#M%xyyTomUJyIZE1{q2^e-?p%p6)+w z&%|WWCs-3$^>Jn~Ixlp!4RjeRkUrlTpT52PnYku2H-MR?pD}@+aqtQ9bBE2s&bMRUXgp!jX!n~$}Z8KNY=a$bCsAwaP1j!C{hKArHSeS?$anO1&jwy zBwt`N@$~_*M6+VNV|!6OSO06|*Whtuz9V>*LAUSHJ*f=-ZYNK5tbqZd!3s+oOw*Tg zv)QM9^vUqQCo7r703>HKRE~A50l&f&DSTSDsV7o>}x>a7vHz1&V@+_7e3P@rtlJ$zsx z|LP--KT$TCDMw`Mdg{dLO3fR9c(Y6e=R)qKi0Yfo)TAekLtu-9pz~fus2C zr-bkFJ&Sw~Tlw(MRPv=RC&kN3ApFcI|Bd>dNujf`ZnoxV^j++!SbXS!7{K%Pj+*=z zL;6NIhsOsc%<(qVDVUC^Q6IC1z;n$`qFHv5{alT`?ZX?3VTk+3wZ9!Ixe6(N#qHc< z<>27Cg_a1Ih1?N`90)#F(J5?Yv-V84wY2x!dh`iwPt5qWgX%1tHs9+*zSK)wmS^6pANh|EVAj!`QLtPWvNlACrjx3 zHR+Ny&IYy$AJ^CyPC$YgGRF7Z52wD4ng$@C@gSelLg{XR%rj?$@biU0$1kE~x7tmU+dr_*200d6K;fUnm!3}-e+WQIYn{uER_3Gm9J)T}r6PHB(%Ni(*LNC?N zzibO{wSY`=Z!;pUOWhMo8fd1br^DasAtJX(0)m##{2xRh{9y$0l4O2Z_HT5(8u1Bf z3jFvXD)oveEdKzanrr5rot7|txBS5l!nkw9ZoPP><~;$vpE}~0#-g;qi7Y4&H&9xA|HIWuHCI4!nj$-sQ7XJZQ`XVBNHva{LrjAjeT%#XWAMt`|R48MV**d$> zE6yRV3wBUnbu=rgW#8RLDbB_mEy%IUfh+OHw8R4~NFS=dgTP9@RllN6n^2?Xu`D%a z1$vbU+-!hT)ssMX4aVt91I;|`s1kbjbt+9Kw1p+xb}azSmc5ZUUya*^K1DZN{?Hcx z%7r&sn>IDz&~W#nALCKti}Thr-t~BhD8~uAkfi80)>O@s?7$prn^v@WU%SX`kB`&u zlCPkl;Qdyr&}lyR!*R*zT5@01>j#YX>z*Et=14fab!OZNkiSJ#&s=a5s+On!277Cc zLg^%Bi>c^Z+rMI5J&LI%Eh%(9kF_aXixgPBF8y~)29c(<(8gxSxh^qQ_0Y6X@TO3ygXqmw z?#6MaJAY6Q{0P+y3SnX$PtkH>*<%}J_~kC#?wG!@!Kr54`Y_vntqTw z2u6%^J2Edczgxn>T7NLn&9}ge5?gX#dhLDO+;UnP8tA;@0g7I4V?ES|FKMmw5PxbZ zhK1dm22+hfhb~=!ToC8Z>CAtQJYO&`70!O=uBb4kBW;u;*F$u?p3&Oz189Rx|doq#UVja$E&500k;CRL)q?4$WWR+e5YyDYGv~@{b?!Hm3EBE>$pW2(XHE^|nF9?zi;I#Rs z-c=M9?tU)6fsTG0nu$`?lhGUf{E^_t3fWup1m8oPgX?2jf}aJ{(w}Vt$bY~~o|T4f z?7@CSi?6mm>>3sx{I}`WWkW-Wof^VJL?!yDaM9;O*|Ce(pr`e-fUD2J%^`ChrHPTF z-ksqkz!Z+T4QD$yK*kGd4Sn!W4zyUbe`joDW@k)Zfjj`D*qg|?PTF2;w>#IK&{U#C zqqJJoh?&m@m-7XY3zipda4TC)>I;y>TuOVOjJsOu-0n~g?vbC=RHskziadpX%{Qn& zB(DPfiVVh>dbl@dx!SIg4lXLUYb1ShE-cW;l<&8TWvfv9@VlG(0`*g>FIpaCLDQnw z^`f`f-@iy6A)R|Sx;LNl@#k@N^N^s^KU^5=zcOmbKy6-_l+D}OE&Juont@Si8eI{) zI-b2_@fi+cLw;xgTKH$=vqi*tfPpkLvrqkNjXYX>7fAH5J=vir5|88ta;8;4>s}C- z+Z&@!hlO}6S##4K2|S#d{%GwLV#HJH-FX?7?mi_BE06p94P8`_QhU3)BCL_l2li?V z|D;xNR$UF7jV6E;3hJ6JN31p zSS|C5uy<)OF5glUBx*xsIQpHNK8f~xD?EPFhumkoHr9ybb$jCyygLREf$;v41HHdd z)s^3@dx8kkLvTPe%av;;;>9Dk*!3eEwy?~{r6MNvd-0`Fx~{1eUBV@?)I^7toyEWB zHi_(6bv$XOWYyST?Q4^@A>L;jvWeqVPgUMJv2n;B9QUaHLteKCeq&NtkZn7|_&UOs>E4L)etXS5mUc6&o&=Mc$b}9r2_PC}t3otqG7SsG zQ^nu&WU1X+pRU|{`P9*qULh3R;u))PU|~8SG}BlEpVs;56#6r~8j&8H*Hr_R z(XEpr1}3c|*(evLdad6-csta@BD5K95-#m0`NWx)#7b7&pWKx$JZaJt!gEIl1Le1{ zWVAaFhr{mnS#3?mieEXb|9lKK;;evdSN0Rjwk`5+dTu+g|0^_-Ij=!sju)o}_ejYT zt{t%FNz({jV?3%^&>LkHGx>;RRPL$jU}8hOrqC^FC+Jj8n)8>`a6OrpbSHUXN=a*H zXH~<@Y#;*m_zJ(E;uqz0OP(9VI2ME-y3x*;FL1NG=+h1;+W_;&rhZBkL7;#(5L{rB&%4{Y&ILiHOpzXn{9Wc(Ba zq<>IbuAfjr&d;GMUd5Q`H!<~p#YJ7J#1Nh2>Kde?aTM1(LOAFN;Cra5dUxt~l)H&rZ=&Z^9bmbUv>`nI9v7tarR5Yr1L>hAeU(bBN;N7|38 znO7i#l7qLlgpc%beY~h>%80)cq1oQ@IX(f+JLpW$qlxb;-H-sVdA%CYH|*e83#8;^s5 crpVye!-Nb9?3lnR4gy~1PF=FDvAh}cKO 12 && (newItems.length = 12), apiClient.getItems(apiClient.getCurrentUserId(), { - Recursive: !0, + + if (!newItems.length) { + return; + } + + // Don't put a massive number of Id's onto the query string + if (newItems.length > 12) { + newItems.length = 12; + } + + apiClient.getItems(apiClient.getCurrentUserId(), { + + Recursive: true, Limit: 3, Filters: "IsNotFolder", SortBy: "DateCreated", SortOrder: "Descending", - Ids: newItems.join(","), + Ids: newItems.join(','), MediaTypes: "Audio,Video", - EnableTotalRecordCount: !1 - }).then(function(result) { - for (var items = result.Items, i = 0, length = items.length; i < length; i++) showNewItemNotification(items[i], apiClient) - })) + EnableTotalRecordCount: false + + }).then(function (result) { + + var items = result.Items; + + for (var i = 0, length = items.length ; i < length; i++) { + + showNewItemNotification(items[i], apiClient); + } + }); } function getIconUrl(name) { - return name = name || "notificationicon.png", require.toUrl(".").split("?")[0] + "/" + name + + name = name || 'notificationicon.png'; + + return require.toUrl('.').split('?')[0] + '/' + name; } function showPackageInstallNotification(apiClient, installation, status) { - apiClient.getCurrentUser().then(function(user) { - if (user.Policy.IsAdministrator) { - var notification = { - tag: "install" + installation.Id, - data: {} - }; - if ("completed" === status ? (notification.title = globalize.translate("sharedcomponents#PackageInstallCompleted").replace("{0}", installation.Name + " " + installation.Version), notification.vibrate = !0) : "cancelled" === status ? notification.title = globalize.translate("sharedcomponents#PackageInstallCancelled").replace("{0}", installation.Name + " " + installation.Version) : "failed" === status ? (notification.title = globalize.translate("sharedcomponents#PackageInstallFailed").replace("{0}", installation.Name + " " + installation.Version), notification.vibrate = !0) : "progress" === status && (notification.title = globalize.translate("sharedcomponents#InstallingPackage").replace("{0}", installation.Name + " " + installation.Version), notification.actions = [{ - action: "cancel-install", - title: globalize.translate("sharedcomponents#ButtonCancel"), - icon: getIconUrl() - }], notification.data.id = installation.id), "progress" === status) { - var percentComplete = Math.round(installation.PercentComplete || 0); - notification.body = percentComplete + "% complete." - } - showNotification(notification, "cancelled" === status ? 5e3 : 0, apiClient) + + apiClient.getCurrentUser().then(function (user) { + + if (!user.Policy.IsAdministrator) { + return; } - }) - } - document.addEventListener("click", onOneDocumentClick), document.addEventListener("keydown", onOneDocumentClick); - var serviceWorkerRegistration; - resetRegistration(), events.on(serverNotifications, "LibraryChanged", function(e, apiClient, data) { - onLibraryChanged(data, apiClient) - }), events.on(serverNotifications, "PackageInstallationCompleted", function(e, apiClient, data) { - showPackageInstallNotification(apiClient, data, "completed") - }), events.on(serverNotifications, "PackageInstallationFailed", function(e, apiClient, data) { - showPackageInstallNotification(apiClient, data, "failed") - }), events.on(serverNotifications, "PackageInstallationCancelled", function(e, apiClient, data) { - showPackageInstallNotification(apiClient, data, "cancelled") - }), events.on(serverNotifications, "PackageInstalling", function(e, apiClient, data) { - showPackageInstallNotification(apiClient, data, "progress") - }), events.on(serverNotifications, "ServerShuttingDown", function(e, apiClient, data) { - showNotification({ - tag: "restart" + apiClient.serverInfo().Id, - title: globalize.translate("sharedcomponents#ServerNameIsShuttingDown", apiClient.serverInfo().Name) - }, 0, apiClient) - }), events.on(serverNotifications, "ServerRestarting", function(e, apiClient, data) { - showNotification({ - tag: "restart" + apiClient.serverInfo().Id, - title: globalize.translate("sharedcomponents#ServerNameIsRestarting", apiClient.serverInfo().Name) - }, 0, apiClient) - }), events.on(serverNotifications, "RestartRequired", function(e, apiClient) { - var serverId = apiClient.serverInfo().Id, - notification = { - tag: "restart" + serverId, - title: globalize.translate("sharedcomponents#PleaseRestartServerName", apiClient.serverInfo().Name) + + var notification = { + tag: "install" + installation.Id, + data: {} }; - notification.actions = [{ - action: "restart", - title: globalize.translate("sharedcomponents#ButtonRestart"), - icon: getIconUrl() - }], showNotification(notification, 0, apiClient) - }) + + if (status === 'completed') { + notification.title = globalize.translate('sharedcomponents#PackageInstallCompleted').replace('{0}', installation.Name + ' ' + installation.Version); + notification.vibrate = true; + } + else if (status === 'cancelled') { + notification.title = globalize.translate('sharedcomponents#PackageInstallCancelled').replace('{0}', installation.Name + ' ' + installation.Version); + } + else if (status === 'failed') { + notification.title = globalize.translate('sharedcomponents#PackageInstallFailed').replace('{0}', installation.Name + ' ' + installation.Version); + notification.vibrate = true; + } + else if (status === 'progress') { + notification.title = globalize.translate('sharedcomponents#InstallingPackage').replace('{0}', installation.Name + ' ' + installation.Version); + + notification.actions = + [ + { + action: 'cancel-install', + title: globalize.translate('sharedcomponents#ButtonCancel'), + icon: getIconUrl() + } + ]; + + notification.data.id = installation.id; + } + + if (status === 'progress') { + + var percentComplete = Math.round(installation.PercentComplete || 0); + + notification.body = percentComplete + '% complete.'; + } + + var timeout = status === 'cancelled' ? 5000 : 0; + + showNotification(notification, timeout, apiClient); + }); + } + + events.on(serverNotifications, 'LibraryChanged', function (e, apiClient, data) { + onLibraryChanged(data, apiClient); + }); + + events.on(serverNotifications, 'PackageInstallationCompleted', function (e, apiClient, data) { + showPackageInstallNotification(apiClient, data, "completed"); + }); + + events.on(serverNotifications, 'PackageInstallationFailed', function (e, apiClient, data) { + showPackageInstallNotification(apiClient, data, "failed"); + }); + + events.on(serverNotifications, 'PackageInstallationCancelled', function (e, apiClient, data) { + showPackageInstallNotification(apiClient, data, "cancelled"); + }); + + events.on(serverNotifications, 'PackageInstalling', function (e, apiClient, data) { + showPackageInstallNotification(apiClient, data, "progress"); + }); + + events.on(serverNotifications, 'ServerShuttingDown', function (e, apiClient, data) { + var serverId = apiClient.serverInfo().Id; + var notification = { + tag: "restart" + serverId, + title: globalize.translate('sharedcomponents#ServerNameIsShuttingDown', apiClient.serverInfo().Name) + }; + showNotification(notification, 0, apiClient); + }); + + events.on(serverNotifications, 'ServerRestarting', function (e, apiClient, data) { + var serverId = apiClient.serverInfo().Id; + var notification = { + tag: "restart" + serverId, + title: globalize.translate('sharedcomponents#ServerNameIsRestarting', apiClient.serverInfo().Name) + }; + showNotification(notification, 0, apiClient); + }); + + events.on(serverNotifications, 'RestartRequired', function (e, apiClient) { + + var serverId = apiClient.serverInfo().Id; + var notification = { + tag: "restart" + serverId, + title: globalize.translate('sharedcomponents#PleaseRestartServerName', apiClient.serverInfo().Name) + }; + + notification.actions = + [ + { + action: 'restart', + title: globalize.translate('sharedcomponents#ButtonRestart'), + icon: getIconUrl() + } + ]; + + showNotification(notification, 0, apiClient); + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.css b/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.css index 1d799ff06d..1a6972e049 100644 --- a/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.css +++ b/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.css @@ -1,103 +1,74 @@ -.nowPlayingBarInfoContainer { - display: -webkit-box; - display: -webkit-flex; +.nowPlayingBarInfoContainer { display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; height: 100%; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; flex-grow: 1; - overflow: hidden + overflow: hidden; } +/* Now playing bar */ .nowPlayingBar { + /* Above everything, except for the video player and popup overlays */ text-align: center; will-change: transform; contain: layout style; - -webkit-transition: -webkit-transform .2s ease-out; - -o-transition: transform .2s ease-out; - transition: transform .2s ease-out + transition: transform 200ms ease-out; } .nowPlayingBar-hidden { - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0) + transform: translate3d(0,100%,0); } .nowPlayingBarTop { - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -webkit-flex-direction: row; flex-direction: row; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; height: 4.2em; position: relative; - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center + justify-content: center; } -.mediaButton, -.nowPlayingBarUserDataButtons .btnUserItemRating { +.mediaButton, .nowPlayingBarUserDataButtons .btnUserItemRating { vertical-align: middle; margin: 0; - text-align: center + text-align: center; } .mediaButton { - font-size: 120% + font-size: 120%; } .nowPlayingBar .nowPlayingImage { background-position: center center; background-repeat: no-repeat; - -webkit-background-size: contain; background-size: contain; height: 70%; width: 4.2em; - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } .nowPlayingBarText { overflow: hidden; white-space: nowrap; - -o-text-overflow: ellipsis; text-overflow: ellipsis; vertical-align: middle; text-align: left; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; flex-grow: 1; font-size: 92%; margin-right: 2.4em; - margin-left: 1em + margin-left: 1em; } .nowPlayingBarCenter { vertical-align: middle; text-align: center; + /* Need this to make sure it's on top of nowPlayingBarPositionContainer so that buttons are fully clickable */ z-index: 2; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; flex-grow: 1; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; justify-content: center; - position: absolute + position: absolute; } .nowPlayingBarPositionContainer { @@ -105,81 +76,81 @@ left: 0; top: -.56em; right: 0; - z-index: 1 + z-index: 1; +} + +.headroom--unpinned .nowPlayingBarPositionContainer { + display: none; } -.headroom--unpinned .nowPlayingBarPositionContainer, .noMediaProgress .nowPlayingBarPositionContainer { - display: none + display: none; } .nowPlayingBarRight { position: relative; margin: 0 .5em 0 auto; + /* Need this to make sure it's on top of nowPlayingBarPositionContainer so that buttons are fully clickable */ z-index: 2; - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-flex-shrink: 0; - flex-shrink: 0 + flex-shrink: 0; } .nowPlayingBarCurrentTime { vertical-align: middle; text-align: center; display: inline-block; - padding-left: 1.5em + padding-left: 1.5em; } .nowPlayingBarVolumeSliderContainer { - margin-right: 2em + margin-right: 2em; } .nowPlayingBarUserDataButtons { display: inline-block; margin-left: 1em; - margin-right: 1em + margin-right: 1em; } .nowPlayingBarPositionSlider::-webkit-slider-thumb { width: 1.2em !important; - height: 1.2em !important + height: 1.2em !important; } -@media all and (max-width:87.5em) { +@media all and (max-width: 87.5em) { + .nowPlayingBarUserDataButtons { - display: none + display: none; } } -@media all and (max-width:68.75em) { +@media all and (max-width: 68.75em) { - .nowPlayingBar .muteButton, - .nowPlayingBar .unmuteButton, - .nowPlayingBarVolumeSliderContainer { - display: none !important + .nowPlayingBarVolumeSliderContainer, .nowPlayingBar .muteButton, .nowPlayingBar .unmuteButton { + display: none !important; } } -@media all and (max-width:50em) { +@media all and (max-width: 50em) { + .nowPlayingBarCenter { - display: none !important + display: none !important; } .toggleRepeatButton { - display: none + display: none; } } -@media all and (min-width:50em) { +@media all and (min-width: 50em) { + .nowPlayingBarRight .playPauseButton { - display: none + display: none; } .nowPlayingBarInfoContainer { - max-width: 40% + max-width: 40%; } -} \ No newline at end of file +} diff --git a/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js b/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js index feded12a2a..3d55a342e5 100644 --- a/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js +++ b/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js @@ -1,270 +1,782 @@ -define(["require", "datetime", "itemHelper", "events", "browser", "imageLoader", "layoutManager", "playbackManager", "nowPlayingHelper", "apphost", "dom", "connectionManager", "paper-icon-button-light", "emby-ratingbutton"], function(require, datetime, itemHelper, events, browser, imageLoader, layoutManager, playbackManager, nowPlayingHelper, appHost, dom, connectionManager) { - "use strict"; +define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', 'layoutManager', 'playbackManager', 'nowPlayingHelper', 'apphost', 'dom', 'connectionManager', 'paper-icon-button-light', 'emby-ratingbutton'], function (require, datetime, itemHelper, events, browser, imageLoader, layoutManager, playbackManager, nowPlayingHelper, appHost, dom, connectionManager) { + 'use strict'; + + var currentPlayer; + var currentPlayerSupportedCommands = []; + + var currentTimeElement; + var nowPlayingImageElement; + var nowPlayingTextElement; + var nowPlayingUserData; + var muteButton; + var volumeSlider; + var volumeSliderContainer; + var playPauseButtons; + var positionSlider; + var toggleRepeatButton; + var toggleRepeatButtonIcon; + + var lastUpdateTime = 0; + var lastPlayerState = {}; + var isEnabled; + var currentRuntimeTicks = 0; + + var isVisibilityAllowed = true; function getNowPlayingBarHtml() { - var html = ""; - return html += '
', html += '
', html += '
', html += '', html += "
", html += '
', html += '
', html += '
', html += "
", html += '
', html += '', html += '', html += '', html += '', html += '
', html += "
", html += '
', html += '', html += '
', html += '', html += "
", html += '', html += '
', html += "
", html += '', html += '', html += "
", html += "
", html += "
" + + var html = ''; + + html += '
'; + + html += '
'; + html += '
'; + html += ''; + html += '
'; + + html += '
'; + html += '
'; + html += '
'; + html += '
'; + + // The onclicks are needed due to the return false above + html += '
'; + + html += ''; + + html += ''; + + html += ''; + html += ''; + + html += '
'; + html += '
'; + + html += '
'; + + html += ''; + + html += '
'; + html += ''; + html += '
'; + + html += ''; + + html += '
'; + html += '
'; + + html += ''; + html += ''; + + html += '
'; + html += '
'; + + html += '
'; + + return html; } function onSlideDownComplete() { - this.classList.add("hide") + + this.classList.add('hide'); } function slideDown(elem) { - elem.offsetWidth, elem.classList.add("nowPlayingBar-hidden"), dom.addEventListener(elem, dom.whichTransitionEvent(), onSlideDownComplete, { - once: !0 - }) + + // trigger reflow + void elem.offsetWidth; + + elem.classList.add('nowPlayingBar-hidden'); + + dom.addEventListener(elem, dom.whichTransitionEvent(), onSlideDownComplete, { + once: true + }); } function slideUp(elem) { + dom.removeEventListener(elem, dom.whichTransitionEvent(), onSlideDownComplete, { - once: !0 - }), elem.classList.remove("hide"), elem.offsetWidth, elem.classList.remove("nowPlayingBar-hidden") + once: true + }); + + elem.classList.remove('hide'); + + // trigger reflow + void elem.offsetWidth; + + elem.classList.remove('nowPlayingBar-hidden'); } function onPlayPauseClick() { - playbackManager.playPause(currentPlayer) + playbackManager.playPause(currentPlayer); } function bindEvents(elem) { - currentTimeElement = elem.querySelector(".nowPlayingBarCurrentTime"), nowPlayingImageElement = elem.querySelector(".nowPlayingImage"), nowPlayingTextElement = elem.querySelector(".nowPlayingBarText"), nowPlayingUserData = elem.querySelector(".nowPlayingBarUserDataButtons"), muteButton = elem.querySelector(".muteButton"), muteButton.addEventListener("click", function() { - currentPlayer && playbackManager.toggleMute(currentPlayer) - }), elem.querySelector(".stopButton").addEventListener("click", function() { - currentPlayer && playbackManager.stop(currentPlayer) - }); - var i, length; - for (playPauseButtons = elem.querySelectorAll(".playPauseButton"), i = 0, length = playPauseButtons.length; i < length; i++) playPauseButtons[i].addEventListener("click", onPlayPauseClick); - elem.querySelector(".nextTrackButton").addEventListener("click", function() { - currentPlayer && playbackManager.nextTrack(currentPlayer) - }), elem.querySelector(".previousTrackButton").addEventListener("click", function() { - currentPlayer && playbackManager.previousTrack(currentPlayer) - }), elem.querySelector(".remoteControlButton").addEventListener("click", showRemoteControl), toggleRepeatButton = elem.querySelector(".toggleRepeatButton"), toggleRepeatButton.addEventListener("click", function() { - if (currentPlayer) switch (playbackManager.getRepeatMode(currentPlayer)) { - case "RepeatAll": - playbackManager.setRepeatMode("RepeatOne", currentPlayer); - break; - case "RepeatOne": - playbackManager.setRepeatMode("RepeatNone", currentPlayer); - break; - default: - playbackManager.setRepeatMode("RepeatAll", currentPlayer) - } - }), toggleRepeatButtonIcon = toggleRepeatButton.querySelector("i"), volumeSlider = elem.querySelector(".nowPlayingBarVolumeSlider"), volumeSliderContainer = elem.querySelector(".nowPlayingBarVolumeSliderContainer"), appHost.supports("physicalvolumecontrol") ? volumeSliderContainer.classList.add("hide") : volumeSliderContainer.classList.remove("hide"), volumeSlider.addEventListener("change", function() { - currentPlayer && currentPlayer.setVolume(this.value) - }), positionSlider = elem.querySelector(".nowPlayingBarPositionSlider"), positionSlider.addEventListener("change", function() { + + currentTimeElement = elem.querySelector('.nowPlayingBarCurrentTime'); + nowPlayingImageElement = elem.querySelector('.nowPlayingImage'); + nowPlayingTextElement = elem.querySelector('.nowPlayingBarText'); + nowPlayingUserData = elem.querySelector('.nowPlayingBarUserDataButtons'); + + muteButton = elem.querySelector('.muteButton'); + muteButton.addEventListener('click', function () { + if (currentPlayer) { - var newPercent = parseFloat(this.value); - playbackManager.seekPercent(newPercent, currentPlayer) + playbackManager.toggleMute(currentPlayer); } - }), positionSlider.getBubbleText = function(value) { + + }); + + elem.querySelector('.stopButton').addEventListener('click', function () { + + if (currentPlayer) { + playbackManager.stop(currentPlayer); + } + }); + + var i, length; + playPauseButtons = elem.querySelectorAll('.playPauseButton'); + for (i = 0, length = playPauseButtons.length; i < length; i++) { + playPauseButtons[i].addEventListener('click', onPlayPauseClick); + } + + elem.querySelector('.nextTrackButton').addEventListener('click', function () { + + if (currentPlayer) { + playbackManager.nextTrack(currentPlayer); + } + }); + + elem.querySelector('.previousTrackButton').addEventListener('click', function () { + + if (currentPlayer) { + playbackManager.previousTrack(currentPlayer); + } + }); + + elem.querySelector('.remoteControlButton').addEventListener('click', showRemoteControl); + + toggleRepeatButton = elem.querySelector('.toggleRepeatButton'); + toggleRepeatButton.addEventListener('click', function () { + + if (currentPlayer) { + + switch (playbackManager.getRepeatMode(currentPlayer)) { + case 'RepeatAll': + playbackManager.setRepeatMode('RepeatOne', currentPlayer); + break; + case 'RepeatOne': + playbackManager.setRepeatMode('RepeatNone', currentPlayer); + break; + default: + playbackManager.setRepeatMode('RepeatAll', currentPlayer); + break; + } + } + }); + + toggleRepeatButtonIcon = toggleRepeatButton.querySelector('i'); + + volumeSlider = elem.querySelector('.nowPlayingBarVolumeSlider'); + volumeSliderContainer = elem.querySelector('.nowPlayingBarVolumeSliderContainer'); + + if (appHost.supports('physicalvolumecontrol')) { + volumeSliderContainer.classList.add('hide'); + } else { + volumeSliderContainer.classList.remove('hide'); + } + + volumeSlider.addEventListener('change', function () { + + if (currentPlayer) { + currentPlayer.setVolume(this.value); + } + + }); + + positionSlider = elem.querySelector('.nowPlayingBarPositionSlider'); + positionSlider.addEventListener('change', function () { + + if (currentPlayer) { + + var newPercent = parseFloat(this.value); + + playbackManager.seekPercent(newPercent, currentPlayer); + } + + }); + + positionSlider.getBubbleText = function (value) { + var state = lastPlayerState; - if (!state || !state.NowPlayingItem || !currentRuntimeTicks) return "--:--"; + + if (!state || !state.NowPlayingItem || !currentRuntimeTicks) { + return '--:--'; + } + var ticks = currentRuntimeTicks; - return ticks /= 100, ticks *= value, datetime.getDisplayRunningTime(ticks) - }, elem.addEventListener("click", function(e) { - dom.parentWithTag(e.target, ["BUTTON", "INPUT", "A"]) || showRemoteControl() - }) + ticks /= 100; + ticks *= value; + + return datetime.getDisplayRunningTime(ticks); + }; + + elem.addEventListener('click', function (e) { + + if (!dom.parentWithTag(e.target, ['BUTTON', 'INPUT', 'A'])) { + showRemoteControl(0); + } + }); } function showRemoteControl() { - require(["appRouter"], function(appRouter) { - appRouter.showNowPlaying() - }) + + require(['appRouter'], function (appRouter) { + appRouter.showNowPlaying(); + }); } + var nowPlayingBarElement; function getNowPlayingBar() { - return nowPlayingBarElement ? Promise.resolve(nowPlayingBarElement) : new Promise(function(resolve, reject) { - require(["appFooter-shared", "itemShortcuts", "css!./nowplayingbar.css", "emby-slider"], function(appfooter, itemShortcuts) { + + if (nowPlayingBarElement) { + return Promise.resolve(nowPlayingBarElement); + } + + return new Promise(function (resolve, reject) { + + require(['appFooter-shared', 'itemShortcuts', 'css!./nowplayingbar.css', 'emby-slider'], function (appfooter, itemShortcuts) { + var parentContainer = appfooter.element; - if (nowPlayingBarElement = parentContainer.querySelector(".nowPlayingBar")) return void resolve(nowPlayingBarElement); - parentContainer.insertAdjacentHTML("afterbegin", getNowPlayingBarHtml()), nowPlayingBarElement = parentContainer.querySelector(".nowPlayingBar"), browser.safari && browser.slow && nowPlayingBarElement.classList.add("noMediaProgress"), itemShortcuts.on(nowPlayingBarElement), bindEvents(nowPlayingBarElement), resolve(nowPlayingBarElement) - }) - }) + nowPlayingBarElement = parentContainer.querySelector('.nowPlayingBar'); + + if (nowPlayingBarElement) { + resolve(nowPlayingBarElement); + return; + } + + parentContainer.insertAdjacentHTML('afterbegin', getNowPlayingBarHtml()); + nowPlayingBarElement = parentContainer.querySelector('.nowPlayingBar'); + + if (browser.safari && browser.slow) { + // Not handled well here. The wrong elements receive events, bar doesn't update quickly enough, etc. + nowPlayingBarElement.classList.add('noMediaProgress'); + } + + itemShortcuts.on(nowPlayingBarElement); + + bindEvents(nowPlayingBarElement); + resolve(nowPlayingBarElement); + }); + }); } function showButton(button) { - button.classList.remove("hide") + button.classList.remove('hide'); } function hideButton(button) { - button.classList.add("hide") + button.classList.add('hide'); } function updatePlayPauseState(isPaused) { + var i, length; - if (playPauseButtons) - if (isPaused) - for (i = 0, length = playPauseButtons.length; i < length; i++) playPauseButtons[i].querySelector("i").innerHTML = "play_arrow"; - else - for (i = 0, length = playPauseButtons.length; i < length; i++) playPauseButtons[i].querySelector("i").innerHTML = "pause" + + if (playPauseButtons) { + if (isPaused) { + + for (i = 0, length = playPauseButtons.length; i < length; i++) { + playPauseButtons[i].querySelector('i').innerHTML = 'play_arrow'; + } + + } else { + + for (i = 0, length = playPauseButtons.length; i < length; i++) { + playPauseButtons[i].querySelector('i').innerHTML = 'pause'; + } + } + } } function updatePlayerStateInternal(event, state, player) { - showNowPlayingBar(), lastPlayerState = state; - var playerInfo = playbackManager.getPlayerInfo(), - playState = state.PlayState || {}; + + showNowPlayingBar(); + + lastPlayerState = state; + + var playerInfo = playbackManager.getPlayerInfo(); + + var playState = state.PlayState || {}; + updatePlayPauseState(playState.IsPaused); + var supportedCommands = playerInfo.supportedCommands; - if (currentPlayerSupportedCommands = supportedCommands, -1 === supportedCommands.indexOf("SetRepeatMode") ? toggleRepeatButton.classList.add("hide") : toggleRepeatButton.classList.remove("hide"), updateRepeatModeDisplay(playState.RepeatMode), updatePlayerVolumeState(playState.IsMuted, playState.VolumeLevel), positionSlider && !positionSlider.dragging) { - positionSlider.disabled = !playState.CanSeek; - var isProgressClear = state.MediaSource && null == state.MediaSource.RunTimeTicks; - positionSlider.setIsClear(isProgressClear) + currentPlayerSupportedCommands = supportedCommands; + + if (supportedCommands.indexOf('SetRepeatMode') === -1) { + toggleRepeatButton.classList.add('hide'); + } else { + toggleRepeatButton.classList.remove('hide'); } - updateTimeDisplay(playState.PositionTicks, (state.NowPlayingItem || {}).RunTimeTicks, playbackManager.getBufferedRanges(player)), updateNowPlayingInfo(state) + + updateRepeatModeDisplay(playState.RepeatMode); + + updatePlayerVolumeState(playState.IsMuted, playState.VolumeLevel); + + if (positionSlider && !positionSlider.dragging) { + positionSlider.disabled = !playState.CanSeek; + + // determines if both forward and backward buffer progress will be visible + var isProgressClear = state.MediaSource && state.MediaSource.RunTimeTicks == null; + positionSlider.setIsClear(isProgressClear); + } + + var nowPlayingItem = state.NowPlayingItem || {}; + updateTimeDisplay(playState.PositionTicks, nowPlayingItem.RunTimeTicks, playbackManager.getBufferedRanges(player)); + + updateNowPlayingInfo(state); } function updateRepeatModeDisplay(repeatMode) { - "RepeatAll" === repeatMode ? (toggleRepeatButtonIcon.innerHTML = "repeat", toggleRepeatButton.classList.add("repeatButton-active")) : "RepeatOne" === repeatMode ? (toggleRepeatButtonIcon.innerHTML = "repeat_one", toggleRepeatButton.classList.add("repeatButton-active")) : (toggleRepeatButtonIcon.innerHTML = "repeat", toggleRepeatButton.classList.remove("repeatButton-active")) + + if (repeatMode === 'RepeatAll') { + toggleRepeatButtonIcon.innerHTML = "repeat"; + toggleRepeatButton.classList.add('repeatButton-active'); + } + else if (repeatMode === 'RepeatOne') { + toggleRepeatButtonIcon.innerHTML = "repeat_one"; + toggleRepeatButton.classList.add('repeatButton-active'); + } else { + toggleRepeatButtonIcon.innerHTML = "repeat"; + toggleRepeatButton.classList.remove('repeatButton-active'); + } } function updateTimeDisplay(positionTicks, runtimeTicks, bufferedRanges) { - if (positionSlider && !positionSlider.dragging) + + // See bindEvents for why this is necessary + if (positionSlider && !positionSlider.dragging) { if (runtimeTicks) { + var pct = positionTicks / runtimeTicks; - pct *= 100, positionSlider.value = pct - } else positionSlider.value = 0; - if (positionSlider && positionSlider.setBufferedRanges(bufferedRanges, runtimeTicks, positionTicks), currentTimeElement) { - var timeText = null == positionTicks ? "--:--" : datetime.getDisplayRunningTime(positionTicks); - runtimeTicks && (timeText += " / " + datetime.getDisplayRunningTime(runtimeTicks)), currentTimeElement.innerHTML = timeText + pct *= 100; + + positionSlider.value = pct; + + } else { + + positionSlider.value = 0; + } + } + + if (positionSlider) { + positionSlider.setBufferedRanges(bufferedRanges, runtimeTicks, positionTicks); + } + + if (currentTimeElement) { + + var timeText = positionTicks == null ? '--:--' : datetime.getDisplayRunningTime(positionTicks); + + if (runtimeTicks) { + timeText += " / " + datetime.getDisplayRunningTime(runtimeTicks); + } + + currentTimeElement.innerHTML = timeText; } } function updatePlayerVolumeState(isMuted, volumeLevel) { - var supportedCommands = currentPlayerSupportedCommands, - showMuteButton = !0, - showVolumeSlider = !0; - 1 === supportedCommands.indexOf("ToggleMute") && (showMuteButton = !1), muteButton.querySelector("i").innerHTML = isMuted ? "" : "", -1 === supportedCommands.indexOf("SetVolume") && (showVolumeSlider = !1), currentPlayer.isLocalPlayer && appHost.supports("physicalvolumecontrol") && (showMuteButton = !1, showVolumeSlider = !1), showMuteButton ? showButton(muteButton) : hideButton(muteButton), volumeSlider && (showVolumeSlider ? volumeSliderContainer.classList.remove("hide") : volumeSliderContainer.classList.add("hide"), volumeSlider.dragging || (volumeSlider.value = volumeLevel || 0)) + + var supportedCommands = currentPlayerSupportedCommands; + + var showMuteButton = true; + var showVolumeSlider = true; + + if (supportedCommands.indexOf('ToggleMute') === -1) { + showMuteButton = false; + } + + if (isMuted) { + muteButton.querySelector('i').innerHTML = ''; + } else { + muteButton.querySelector('i').innerHTML = ''; + } + + if (supportedCommands.indexOf('SetVolume') === -1) { + showVolumeSlider = false; + } + + if (currentPlayer.isLocalPlayer && appHost.supports('physicalvolumecontrol')) { + showMuteButton = false; + showVolumeSlider = false; + } + + if (showMuteButton) { + showButton(muteButton); + } else { + hideButton(muteButton); + } + + // See bindEvents for why this is necessary + if (volumeSlider) { + + if (showVolumeSlider) { + volumeSliderContainer.classList.remove('hide'); + } else { + volumeSliderContainer.classList.add('hide'); + } + + if (!volumeSlider.dragging) { + volumeSlider.value = volumeLevel || 0; + } + } } function getTextActionButton(item, text, serverId) { - text || (text = itemHelper.getDisplayName(item)); + + if (!text) { + text = itemHelper.getDisplayName(item); + } + var html = '" + html += text; + html += ''; + + return html; } function seriesImageUrl(item, options) { - if (!item) throw new Error("item cannot be null!"); - if ("Episode" !== item.Type) return null; - if (options = options || {}, options.type = options.type || "Primary", "Primary" === options.type && item.SeriesPrimaryImageTag) return options.tag = item.SeriesPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - if ("Thumb" === options.type) { - if (item.SeriesThumbImageTag) return options.tag = item.SeriesThumbImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - if (item.ParentThumbImageTag) return options.tag = item.ParentThumbImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options) + + if (!item) { + throw new Error('item cannot be null!'); } - return null + + if (item.Type !== 'Episode') { + return null; + } + + options = options || {}; + options.type = options.type || "Primary"; + + if (options.type === 'Primary') { + + if (item.SeriesPrimaryImageTag) { + + options.tag = item.SeriesPrimaryImageTag; + + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + } + } + + if (options.type === 'Thumb') { + + if (item.SeriesThumbImageTag) { + + options.tag = item.SeriesThumbImageTag; + + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + } + if (item.ParentThumbImageTag) { + + options.tag = item.ParentThumbImageTag; + + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options); + } + } + + return null; } function imageUrl(item, options) { - if (!item) throw new Error("item cannot be null!"); - return options = options || {}, options.type = options.type || "Primary", item.ImageTags && item.ImageTags[options.type] ? (options.tag = item.ImageTags[options.type], connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options)) : item.AlbumId && item.AlbumPrimaryImageTag ? (options.tag = item.AlbumPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options)) : null + + if (!item) { + throw new Error('item cannot be null!'); + } + + options = options || {}; + options.type = options.type || "Primary"; + + if (item.ImageTags && item.ImageTags[options.type]) { + + options.tag = item.ImageTags[options.type]; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options); + } + + if (item.AlbumId && item.AlbumPrimaryImageTag) { + + options.tag = item.AlbumPrimaryImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options); + } + + return null; } + var currentImgUrl; function updateNowPlayingInfo(state) { - var nowPlayingItem = state.NowPlayingItem, - textLines = nowPlayingItem ? nowPlayingHelper.getNowPlayingNames(nowPlayingItem) : []; - textLines.length > 1 && (textLines[1].secondary = !0); + + var nowPlayingItem = state.NowPlayingItem; + + var textLines = nowPlayingItem ? nowPlayingHelper.getNowPlayingNames(nowPlayingItem) : []; + if (textLines.length > 1) { + textLines[1].secondary = true; + } var serverId = nowPlayingItem ? nowPlayingItem.ServerId : null; - nowPlayingTextElement.innerHTML = textLines.map(function(nowPlayingName) { - var cssClass = nowPlayingName.secondary ? ' class="nowPlayingBarSecondaryText"' : ""; - return nowPlayingName.item ? "" + getTextActionButton(nowPlayingName.item, nowPlayingName.text, serverId) + "
" : "" + nowPlayingName.text + "
" - }).join(""); - var url = nowPlayingItem ? seriesImageUrl(nowPlayingItem, { - height: 70 - }) || imageUrl(nowPlayingItem, { - height: 70 - }) : null, - isRefreshing = !1; - if (url !== currentImgUrl && (currentImgUrl = url, isRefreshing = !0, url ? imageLoader.lazyImage(nowPlayingImageElement, url) : nowPlayingImageElement.style.backgroundImage = ""), nowPlayingItem.Id) { - if (isRefreshing) { - var apiClient = connectionManager.getApiClient(nowPlayingItem.ServerId); - apiClient.getItem(apiClient.getCurrentUserId(), nowPlayingItem.Id).then(function(item) { - var userData = item.UserData || {}, - likes = null == userData.Likes ? "" : userData.Likes; - nowPlayingUserData.innerHTML = '' - }) + nowPlayingTextElement.innerHTML = textLines.map(function (nowPlayingName) { + + var cssClass = nowPlayingName.secondary ? ' class="nowPlayingBarSecondaryText"' : ''; + + if (nowPlayingName.item) { + return '' + getTextActionButton(nowPlayingName.item, nowPlayingName.text, serverId) + '
'; } - } else nowPlayingUserData.innerHTML = "" + + return '' + nowPlayingName.text + '
'; + + }).join(''); + + var imgHeight = 70; + + var url = nowPlayingItem ? (seriesImageUrl(nowPlayingItem, { + height: imgHeight + }) || imageUrl(nowPlayingItem, { + height: imgHeight + })) : null; + + var isRefreshing = false; + + if (url !== currentImgUrl) { + currentImgUrl = url; + isRefreshing = true; + + if (url) { + imageLoader.lazyImage(nowPlayingImageElement, url); + } else { + nowPlayingImageElement.style.backgroundImage = ''; + } + } + + if (nowPlayingItem.Id) { + if (isRefreshing) { + + var apiClient = connectionManager.getApiClient(nowPlayingItem.ServerId); + + apiClient.getItem(apiClient.getCurrentUserId(), nowPlayingItem.Id).then(function (item) { + + var userData = item.UserData || {}; + var likes = userData.Likes == null ? '' : userData.Likes; + + nowPlayingUserData.innerHTML = ''; + }); + + } + } else { + nowPlayingUserData.innerHTML = ''; + } } function onPlaybackStart(e, state) { + + //console.log('nowplaying event: ' + e.type); + var player = this; - onStateChanged.call(player, e, state) + + onStateChanged.call(player, e, state); } function onRepeatModeChange(e) { - if (isEnabled) { - var player = this; - updateRepeatModeDisplay(playbackManager.getRepeatMode(player)) + + if (!isEnabled) { + return; } + + var player = this; + + updateRepeatModeDisplay(playbackManager.getRepeatMode(player)); } function showNowPlayingBar() { - if (!isVisibilityAllowed) return void hideNowPlayingBar(); - getNowPlayingBar().then(slideUp) + + if (!isVisibilityAllowed) { + hideNowPlayingBar(); + return; + } + + getNowPlayingBar().then(slideUp); } function hideNowPlayingBar() { - isEnabled = !1; - var elem = document.getElementsByClassName("nowPlayingBar")[0]; - elem && slideDown(elem) - } - function onPlaybackStopped(e, state) { - this.isLocalPlayer ? "Audio" !== state.NextMediaType && hideNowPlayingBar() : state.NextMediaType || hideNowPlayingBar() - } + isEnabled = false; - function onPlayPauseStateChanged(e) { - if (isEnabled) { - updatePlayPauseState(this.paused()) + // Use a timeout to prevent the bar from hiding and showing quickly + // in the event of a stop->play command + + // Don't call getNowPlayingBar here because we don't want to end up creating it just to hide it + var elem = document.getElementsByClassName('nowPlayingBar')[0]; + if (elem) { + + slideDown(elem); } } - function onStateChanged(event, state) { - var player = this; - return !state.NowPlayingItem || layoutManager.tv ? void hideNowPlayingBar() : player.isLocalPlayer && state.NowPlayingItem && "Video" === state.NowPlayingItem.MediaType ? void hideNowPlayingBar() : (isEnabled = !0, nowPlayingBarElement ? void updatePlayerStateInternal(event, state, player) : void getNowPlayingBar().then(function() { - updatePlayerStateInternal(event, state, player) - })) - } + function onPlaybackStopped(e, state) { - function onTimeUpdate(e) { - if (isEnabled) { - var now = (new Date).getTime(); - if (!(now - lastUpdateTime < 700)) { - lastUpdateTime = now; - var player = this; - currentRuntimeTicks = playbackManager.duration(player), updateTimeDisplay(playbackManager.currentTime(player), currentRuntimeTicks, playbackManager.getBufferedRanges(player)) + //console.log('nowplaying event: ' + e.type); + var player = this; + + if (player.isLocalPlayer) { + if (state.NextMediaType !== 'Audio') { + hideNowPlayingBar(); + } + } else { + if (!state.NextMediaType) { + hideNowPlayingBar(); } } } - function releaseCurrentPlayer() { - var player = currentPlayer; - player && (events.off(player, "playbackstart", onPlaybackStart), events.off(player, "statechange", onPlaybackStart), events.off(player, "repeatmodechange", onRepeatModeChange), events.off(player, "playbackstop", onPlaybackStopped), events.off(player, "volumechange", onVolumeChanged), events.off(player, "pause", onPlayPauseStateChanged), events.off(player, "unpause", onPlayPauseStateChanged), events.off(player, "timeupdate", onTimeUpdate), currentPlayer = null, hideNowPlayingBar()) + function onPlayPauseStateChanged(e) { + + if (!isEnabled) { + return; + } + + var player = this; + updatePlayPauseState(player.paused()); } - function onVolumeChanged(e) { - if (isEnabled) { - var player = this; - updatePlayerVolumeState(player.isMuted(), player.getVolume()) + function onStateChanged(event, state) { + + //console.log('nowplaying event: ' + e.type); + var player = this; + + if (!state.NowPlayingItem || layoutManager.tv) { + hideNowPlayingBar(); + return; + } + + if (player.isLocalPlayer && state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') { + hideNowPlayingBar(); + return; + } + + isEnabled = true; + + if (nowPlayingBarElement) { + updatePlayerStateInternal(event, state, player); + return; + } + + getNowPlayingBar().then(function () { + updatePlayerStateInternal(event, state, player); + }); + } + + function onTimeUpdate(e) { + + if (!isEnabled) { + return; + } + + // Try to avoid hammering the document with changes + var now = new Date().getTime(); + if ((now - lastUpdateTime) < 700) { + + return; + } + lastUpdateTime = now; + + var player = this; + currentRuntimeTicks = playbackManager.duration(player); + updateTimeDisplay(playbackManager.currentTime(player), currentRuntimeTicks, playbackManager.getBufferedRanges(player)); + } + + function releaseCurrentPlayer() { + + var player = currentPlayer; + + if (player) { + events.off(player, 'playbackstart', onPlaybackStart); + events.off(player, 'statechange', onPlaybackStart); + events.off(player, 'repeatmodechange', onRepeatModeChange); + events.off(player, 'playbackstop', onPlaybackStopped); + events.off(player, 'volumechange', onVolumeChanged); + events.off(player, 'pause', onPlayPauseStateChanged); + events.off(player, 'unpause', onPlayPauseStateChanged); + events.off(player, 'timeupdate', onTimeUpdate); + + currentPlayer = null; + hideNowPlayingBar(); } } + function onVolumeChanged(e) { + + if (!isEnabled) { + return; + } + + var player = this; + + updatePlayerVolumeState(player.isMuted(), player.getVolume()); + } + function refreshFromPlayer(player) { + var state = playbackManager.getPlayerState(player); - onStateChanged.call(player, { - type: "init" - }, state) + + onStateChanged.call(player, { type: 'init' }, state); } function bindToPlayer(player) { - player !== currentPlayer && (releaseCurrentPlayer(), currentPlayer = player, player && (refreshFromPlayer(player), events.on(player, "playbackstart", onPlaybackStart), events.on(player, "statechange", onPlaybackStart), events.on(player, "repeatmodechange", onRepeatModeChange), events.on(player, "playbackstop", onPlaybackStopped), events.on(player, "volumechange", onVolumeChanged), events.on(player, "pause", onPlayPauseStateChanged), events.on(player, "unpause", onPlayPauseStateChanged), events.on(player, "timeupdate", onTimeUpdate))) + + if (player === currentPlayer) { + return; + } + + releaseCurrentPlayer(); + + currentPlayer = player; + + if (!player) { + return; + } + + refreshFromPlayer(player); + + events.on(player, 'playbackstart', onPlaybackStart); + events.on(player, 'statechange', onPlaybackStart); + events.on(player, 'repeatmodechange', onRepeatModeChange); + events.on(player, 'playbackstop', onPlaybackStopped); + events.on(player, 'volumechange', onVolumeChanged); + events.on(player, 'pause', onPlayPauseStateChanged); + events.on(player, 'unpause', onPlayPauseStateChanged); + events.on(player, 'timeupdate', onTimeUpdate); } - var currentPlayer, currentTimeElement, nowPlayingImageElement, nowPlayingTextElement, nowPlayingUserData, muteButton, volumeSlider, volumeSliderContainer, playPauseButtons, positionSlider, toggleRepeatButton, toggleRepeatButtonIcon, isEnabled, nowPlayingBarElement, currentImgUrl, currentPlayerSupportedCommands = [], - lastUpdateTime = 0, - lastPlayerState = {}, - currentRuntimeTicks = 0, - isVisibilityAllowed = !0; - events.on(playbackManager, "playerchange", function() { - bindToPlayer(playbackManager.getCurrentPlayer()) - }), bindToPlayer(playbackManager.getCurrentPlayer()), document.addEventListener("viewbeforeshow", function(e) { - e.detail.options.enableMediaControl ? isVisibilityAllowed || (isVisibilityAllowed = !0, currentPlayer ? refreshFromPlayer(currentPlayer) : hideNowPlayingBar()) : isVisibilityAllowed && (isVisibilityAllowed = !1, hideNowPlayingBar()) - }) + + events.on(playbackManager, 'playerchange', function () { + bindToPlayer(playbackManager.getCurrentPlayer()); + }); + + bindToPlayer(playbackManager.getCurrentPlayer()); + + document.addEventListener('viewbeforeshow', function (e) { + + if (!e.detail.options.enableMediaControl) { + + if (isVisibilityAllowed) { + isVisibilityAllowed = false; + hideNowPlayingBar(); + } + + } else if (!isVisibilityAllowed) { + + isVisibilityAllowed = true; + if (currentPlayer) { + refreshFromPlayer(currentPlayer); + } else { + hideNowPlayingBar(); + } + } + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/packagemanager.js b/src/bower_components/emby-webcomponents/packagemanager.js index e697028f5c..03ed1006c1 100644 --- a/src/bower_components/emby-webcomponents/packagemanager.js +++ b/src/bower_components/emby-webcomponents/packagemanager.js @@ -1,74 +1,152 @@ -define(["appSettings", "pluginManager"], function(appSettings, pluginManager) { - "use strict"; +define(['appSettings', 'pluginManager'], function (appSettings, pluginManager) { + 'use strict'; + + var settingsKey = 'installedpackages1'; function addPackage(packageManager, pkg) { - packageManager.packagesList = packageManager.packagesList.filter(function(p) { - return p.name !== pkg.name - }), packageManager.packagesList.push(pkg) + + packageManager.packagesList = packageManager.packagesList.filter(function (p) { + + return p.name !== pkg.name; + }); + + packageManager.packagesList.push(pkg); } function removeUrl(url) { - var manifestUrls = JSON.parse(appSettings.get(settingsKey) || "[]"); - manifestUrls = manifestUrls.filter(function(i) { - return i !== url - }), appSettings.set(settingsKey, JSON.stringify(manifestUrls)) + + var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]'); + + manifestUrls = manifestUrls.filter(function (i) { + return i !== url; + }); + + appSettings.set(settingsKey, JSON.stringify(manifestUrls)); } function loadPackage(packageManager, url, throwError) { - return new Promise(function(resolve, reject) { - var xhr = new XMLHttpRequest, - originalUrl = url; - url += -1 === url.indexOf("?") ? "?" : "&", url += "t=" + (new Date).getTime(), xhr.open("GET", url, !0); - var onError = function() { - !0 === throwError ? reject() : (removeUrl(originalUrl), resolve()) + + return new Promise(function (resolve, reject) { + + var xhr = new XMLHttpRequest(); + var originalUrl = url; + url += url.indexOf('?') === -1 ? '?' : '&'; + url += 't=' + new Date().getTime(); + + xhr.open('GET', url, true); + + var onError = function () { + + if (throwError === true) { + reject(); + } else { + removeUrl(originalUrl); + resolve(); + } }; - xhr.onload = function(e) { + + xhr.onload = function (e) { if (this.status < 400) { + var pkg = JSON.parse(this.response); - pkg.url = originalUrl, addPackage(packageManager, pkg); + pkg.url = originalUrl; + + addPackage(packageManager, pkg); + var plugins = pkg.plugins || []; - pkg.plugin && plugins.push(pkg.plugin); - var promises = plugins.map(function(pluginUrl) { - return pluginManager.loadPlugin(packageManager.mapPath(pkg, pluginUrl)) + if (pkg.plugin) { + plugins.push(pkg.plugin); + } + var promises = plugins.map(function (pluginUrl) { + return pluginManager.loadPlugin(packageManager.mapPath(pkg, pluginUrl)); }); - Promise.all(promises).then(resolve, resolve) - } else onError() - }, xhr.onerror = onError, xhr.send() - }) + Promise.all(promises).then(resolve, resolve); + + } else { + onError(); + } + }; + + xhr.onerror = onError; + + xhr.send(); + }); } function PackageManager() { - this.packagesList = [] + + this.packagesList = []; } - var settingsKey = "installedpackages1"; - return PackageManager.prototype.init = function() { - var manifestUrls = JSON.parse(appSettings.get(settingsKey) || "[]"), - instance = this; - return Promise.all(manifestUrls.map(function(u) { - return loadPackage(instance, u) - })).then(function() { - return Promise.resolve() - }, function() { - return Promise.resolve() - }) - }, PackageManager.prototype.packages = function() { - return this.packagesList.slice(0) - }, PackageManager.prototype.install = function(url) { - return loadPackage(this, url, !0).then(function(pkg) { - var manifestUrls = JSON.parse(appSettings.get(settingsKey) || "[]"); - return -1 === manifestUrls.indexOf(url) && (manifestUrls.push(url), appSettings.set(settingsKey, JSON.stringify(manifestUrls))), pkg - }) - }, PackageManager.prototype.uninstall = function(name) { - var pkg = this.packagesList.filter(function(p) { - return p.name === name + + PackageManager.prototype.init = function () { + var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]'); + + var instance = this; + return Promise.all(manifestUrls.map(function (u) { + + return loadPackage(instance, u); + + })).then(function () { + return Promise.resolve(); + }, function () { + return Promise.resolve(); + }); + }; + + PackageManager.prototype.packages = function () { + return this.packagesList.slice(0); + }; + + PackageManager.prototype.install = function (url) { + + return loadPackage(this, url, true).then(function (pkg) { + + var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]'); + + if (manifestUrls.indexOf(url) === -1) { + manifestUrls.push(url); + appSettings.set(settingsKey, JSON.stringify(manifestUrls)); + } + + return pkg; + }); + }; + + PackageManager.prototype.uninstall = function (name) { + + var pkg = this.packagesList.filter(function (p) { + + return p.name === name; })[0]; - return pkg && (this.packagesList = this.packagesList.filter(function(p) { - return p.name !== name - }), removeUrl(pkg.url)), Promise.resolve() - }, PackageManager.prototype.mapPath = function(pkg, pluginUrl) { + + if (pkg) { + + this.packagesList = this.packagesList.filter(function (p) { + + return p.name !== name; + }); + + removeUrl(pkg.url); + } + + return Promise.resolve(); + }; + + PackageManager.prototype.mapPath = function (pkg, pluginUrl) { + var urlLower = pluginUrl.toLowerCase(); - if (0 === urlLower.indexOf("http:") || 0 === urlLower.indexOf("https:") || 0 === urlLower.indexOf("file:")) return pluginUrl; + if (urlLower.indexOf('http:') === 0 || urlLower.indexOf('https:') === 0 || urlLower.indexOf('file:') === 0) { + return pluginUrl; + } + var packageUrl = pkg.url; - return packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf("/")), packageUrl += "/", packageUrl += pluginUrl - }, new PackageManager + packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/')); + + packageUrl += '/'; + packageUrl += pluginUrl; + + return packageUrl; + }; + + return new PackageManager(); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/pagejs/page.js b/src/bower_components/emby-webcomponents/pagejs/page.js index 17b29a434a..ce96fd185e 100644 --- a/src/bower_components/emby-webcomponents/pagejs/page.js +++ b/src/bower_components/emby-webcomponents/pagejs/page.js @@ -1,288 +1,1077 @@ -define([], function() { - "use strict"; +define([], function () { + + 'use strict'; + + /** + * Detect click event + */ + var clickEvent = ('undefined' !== typeof document) && document.ontouchstart ? 'touchstart' : 'click'; + + /** + * To work properly with the URL + * history.location generated polyfill in https://github.com/devote/HTML5-History-API + */ + + var location = ('undefined' !== typeof window) && (window.history.location || window.location); + + /** + * Perform initial dispatch. + */ + + var dispatch = true; + + + /** + * Decode URL components (query string, pathname, hash). + * Accommodates both regular percent encoding and x-www-form-urlencoded format. + */ + var decodeURLComponents = true; + + /** + * Base path. + */ + + var base = ''; + + /** + * Running flag. + */ + + var running; + + /** + * HashBang option + */ + + var hashbang = false; + + var enableHistory = false; + + /** + * Previous context, for capturing + * page exit events. + */ + + var prevContext; + + var prevPageContext; + + /** + * Register `path` with callback `fn()`, + * or route `path`, or redirection, + * or `page.start()`. + * + * page(fn); + * page('*', fn); + * page('/user/:id', load, user); + * page('/user/' + user.id, { some: 'thing' }); + * page('/user/' + user.id); + * page('/from', '/to') + * page(); + * + * @param {String|Function} path + * @param {Function} fn... + * @api public + */ function page(path, fn) { - if ("function" == typeof path) return page("*", path); - if ("function" == typeof fn) - for (var route = new Route(path), i = 1; i < arguments.length; ++i) page.callbacks.push(route.middleware(arguments[i])); - else "string" == typeof path ? page["string" == typeof fn ? "redirect" : "show"](path, fn) : page.start(path) - } + // + if ('function' === typeof path) { + return page('*', path); + } - function unhandled(ctx) { - if (!ctx.handled) { - var current; - current = hashbang ? base + location.hash.replace("#!", "") : location.pathname + location.search, current !== ctx.canonicalPath && (page.stop(), ctx.handled = !1, location.href = ctx.canonicalPath) + // route to + if ('function' === typeof fn) { + var route = new Route(path); + for (var i = 1; i < arguments.length; ++i) { + page.callbacks.push(route.middleware(arguments[i])); + } + // show with [state] + } else if ('string' === typeof path) { + page['string' === typeof fn ? 'redirect' : 'show'](path, fn); + // start [options] + } else { + page.start(path); } } - function decodeURLEncodedURIComponent(val) { - return "string" != typeof val ? val : decodeURLComponents ? decodeURIComponent(val.replace(/\+/g, " ")) : val - } + /** + * Callback functions. + */ - function Context(path, state) { - "/" === path[0] && 0 !== path.indexOf(base) && (path = base + (hashbang ? "#!" : "") + path); - var i = path.indexOf("?"); - if (this.canonicalPath = path, this.path = path.replace(base, "") || "/", hashbang && (this.path = this.path.replace("#!", "") || "/"), this.title = document.title, this.state = state || {}, this.state.path = path, this.querystring = ~i ? decodeURLEncodedURIComponent(path.slice(i + 1)) : "", this.pathname = decodeURLEncodedURIComponent(~i ? path.slice(0, i) : path), this.params = {}, this.hash = "", !hashbang) { - if (!~this.path.indexOf("#")) return; - var parts = this.path.split("#"); - this.path = parts[0], this.hash = decodeURLEncodedURIComponent(parts[1]) || "", this.querystring = this.querystring.split("#")[0] + page.callbacks = []; + page.exits = []; + + /** + * Current path being processed + * @type {String} + */ + page.current = ''; + + /** + * Number of pages navigated to. + * @type {number} + * + * page.len == 0; + * page('/login'); + * page.len == 1; + */ + + page.len = 0; + + /** + * Get or set basepath to `path`. + * + * @param {String} path + * @api public + */ + + page.base = function (path) { + if (0 === arguments.length) { + return base; } - } + base = path; + }; - function Route(path, options) { - options = options || {}, this.path = "*" === path ? "(.*)" : path, this.method = "GET", this.regexp = pathToRegexp(this.path, this.keys = [], options.sensitive, options.strict) - } + /** + * Bind with the given `options`. + * + * Options: + * + * - `click` bind to click events [true] + * - `popstate` bind to popstate [true] + * - `dispatch` perform initial dispatch [true] + * + * @param {Object} options + * @api public + */ - function ignorePopState(event) { - var state = event.state || {}; - return !1 === previousPopState.navigate ? (previousPopState = state, !0) : (previousPopState = state, !1) - } + page.start = function (options) { + options = options || {}; + if (running) { + return; + } + running = true; + if (false === options.dispatch) { + dispatch = false; + } + if (false === options.decodeURLComponents) { + decodeURLComponents = false; + } + if (false !== options.popstate) { + window.addEventListener('popstate', onpopstate, false); + } + if (false !== options.click) { + document.addEventListener(clickEvent, onclick, false); + } + if (options.enableHistory != null) { + enableHistory = options.enableHistory; + } + if (true === options.hashbang) { + hashbang = true; + } + if (!dispatch) { + return; + } - function onclick(e, checkWhich) { - if ((1 === which(e) || !1 === checkWhich) && !(e.metaKey || e.ctrlKey || e.shiftKey || e.defaultPrevented)) { - for (var el = e.target; el && "A" !== el.nodeName;) el = el.parentNode; - if (el && "A" === el.nodeName && !el.hasAttribute("download") && "external" !== el.getAttribute("rel")) { - var link = el.getAttribute("href"); - if ("#" === link) return void e.preventDefault(); - if ((hashbang || el.pathname !== location.pathname || !el.hash && "#" !== link) && !el.target && sameOrigin(el.href)) { - var path = el.pathname + el.search + (el.hash || ""), - orig = path; - 0 === path.indexOf(base) && (path = path.substr(base.length)), hashbang && (path = path.replace("#!", "")), e.preventDefault(), page.show(orig) + var url; + + if (hashbang && ~location.hash.indexOf('#!')) { + + url = location.hash.substr(2); + + var href = location.href.toString(); + if (href.indexOf('?') >= href.indexOf('#!')) { + url += location.search; + } + } + else { + url = location.pathname + location.search + location.hash; + } + + page.replace(url, null, true, dispatch); + }; + + /** + * Unbind click and popstate event handlers. + * + * @api public + */ + + page.stop = function () { + if (!running) { + return; + } + page.current = ''; + page.len = 0; + running = false; + document.removeEventListener(clickEvent, onclick, false); + window.removeEventListener('popstate', onpopstate, false); + }; + + /** + * Show `path` with optional `state` object. + * + * @param {String} path + * @param {Object} state + * @param {Boolean} dispatch + * @return {Context} + * @api public + */ + + page.show = function (path, state, dispatch, push, isBack) { + var ctx = new Context(path, state); + ctx.isBack = isBack; + page.current = ctx.path; + if (false !== dispatch) { + page.dispatch(ctx); + } + if (false !== ctx.handled && false !== push) { + ctx.pushState(); + } + return ctx; + }; + + page.restorePreviousState = function () { + + prevContext = prevPageContext; + page.show(prevContext.pathname, prevContext.state, false, true, false); + }; + + /** + * Goes back in the history + * Back should always let the current route push state and then go back. + * + * @param {String} path - fallback path to go back if no more history exists, if undefined defaults to page.base + * @param {Object} [state] + * @api public + */ + + page.back = function (path, state) { + + if (enableHistory) { + // Keep it simple and mimic browser back + history.back(); + return; + } + + if (page.len > 0) { + // this may need more testing to see if all browsers + // wait for the next tick to go back in history + if (enableHistory) { + history.back(); + } else { + + if (backStack.length > 2) { + backStack.length--; + var previousState = backStack[backStack.length - 1]; + page.show(previousState.path, previousState.state, true, false, true); } } - } - } - - function which(e) { - return e = e || window.event, null === e.which ? e.button : e.which - } - - function sameOrigin(href) { - var origin = location.protocol + "//" + location.hostname; - return location.port && (origin += ":" + location.port), href && 0 === href.indexOf(origin) - } - - function parse(str) { - for (var res, tokens = [], key = 0, index = 0, path = ""; null != (res = PATH_REGEXP.exec(str));) { - var m = res[0], - escaped = res[1], - offset = res.index; - if (path += str.slice(index, offset), index = offset + m.length, escaped) path += escaped[1]; - else { - path && (tokens.push(path), path = ""); - var prefix = res[2], - name = res[3], - capture = res[4], - group = res[5], - suffix = res[6], - asterisk = res[7], - repeat = "+" === suffix || "*" === suffix, - optional = "?" === suffix || "*" === suffix, - delimiter = prefix || "/", - pattern = capture || group || (asterisk ? ".*" : "[^" + delimiter + "]+?"); - tokens.push({ - name: name || key++, - prefix: prefix || "", - delimiter: delimiter, - optional: optional, - repeat: repeat, - pattern: escapeGroup(pattern) - }) - } - } - return index < str.length && (path += str.substr(index)), path && tokens.push(path), tokens - } - - function escapeString(str) { - return str.replace(/([.+*?=^!:${}()[\]|\/])/g, "\\$1") - } - - function escapeGroup(group) { - return group.replace(/([=!:$\/()])/g, "\\$1") - } - - function attachKeys(re, keys) { - return re.keys = keys, re - } - - function flags(options) { - return options.sensitive ? "" : "i" - } - - function regexpToRegexp(path, keys) { - var groups = path.source.match(/\((?!\?)/g); - if (groups) - for (var i = 0; i < groups.length; i++) keys.push({ - name: i, - prefix: null, - delimiter: null, - optional: !1, - repeat: !1, - pattern: null + page.len--; + } else if (path) { + setTimeout(function () { + page.show(path, state); + }); + } else { + setTimeout(function () { + page.show(base, state); }); - return attachKeys(path, keys) - } - - function arrayToRegexp(path, keys, options) { - for (var parts = [], i = 0; i < path.length; i++) parts.push(pathToRegexp(path[i], keys, options).source); - return attachKeys(new RegExp("(?:" + parts.join("|") + ")", flags(options)), keys) - } - - function stringToRegexp(path, keys, options) { - for (var tokens = parse(path), re = tokensToRegExp(tokens, options), i = 0; i < tokens.length; i++) "string" != typeof tokens[i] && keys.push(tokens[i]); - return attachKeys(re, keys) - } - - function tokensToRegExp(tokens, options) { - options = options || {}; - for (var strict = options.strict, end = !1 !== options.end, route = "", lastToken = tokens[tokens.length - 1], endsWithSlash = "string" == typeof lastToken && /\/$/.test(lastToken), i = 0; i < tokens.length; i++) { - var token = tokens[i]; - if ("string" == typeof token) route += escapeString(token); - else { - var prefix = escapeString(token.prefix), - capture = token.pattern; - token.repeat && (capture += "(?:" + prefix + capture + ")*"), capture = token.optional ? prefix ? "(?:" + prefix + "(" + capture + "))?" : "(" + capture + ")?" : prefix + "(" + capture + ")", route += capture - } } - return strict || (route = (endsWithSlash ? route.slice(0, -2) : route) + "(?:\\/(?=$))?"), route += end ? "$" : strict && endsWithSlash ? "" : "(?=\\/|$)", new RegExp("^" + route, flags(options)) - } + }; - function pathToRegexp(path, keys, options) { - return keys = keys || [], isarray(keys) ? options || (options = {}) : (options = keys, keys = []), path instanceof RegExp ? regexpToRegexp(path, keys, options) : isarray(path) ? arrayToRegexp(path, keys, options) : stringToRegexp(path, keys, options) - } - var running, prevContext, prevPageContext, clickEvent = "undefined" != typeof document && document.ontouchstart ? "touchstart" : "click", - location = "undefined" != typeof window && (window.history.location || window.location), - dispatch = !0, - decodeURLComponents = !0, - base = "", - hashbang = !1, - enableHistory = !1; - page.callbacks = [], page.exits = [], page.current = "", page.len = 0, page.base = function(path) { - if (0 === arguments.length) return base; - base = path - }, page.start = function(options) { - if (options = options || {}, !running && (running = !0, !1 === options.dispatch && (dispatch = !1), !1 === options.decodeURLComponents && (decodeURLComponents = !1), !1 !== options.popstate && window.addEventListener("popstate", onpopstate, !1), !1 !== options.click && document.addEventListener(clickEvent, onclick, !1), null != options.enableHistory && (enableHistory = options.enableHistory), !0 === options.hashbang && (hashbang = !0), dispatch)) { - var url; - if (hashbang && ~location.hash.indexOf("#!")) { - url = location.hash.substr(2); - var href = location.href.toString(); - href.indexOf("?") >= href.indexOf("#!") && (url += location.search) - } else url = location.pathname + location.search + location.hash; - page.replace(url, null, !0, dispatch) + page.enableNativeHistory = function () { + return enableHistory; + }; + + page.canGoBack = function () { + if (enableHistory) { + return history.length > 1; } - }, page.stop = function() { - running && (page.current = "", page.len = 0, running = !1, document.removeEventListener(clickEvent, onclick, !1), window.removeEventListener("popstate", onpopstate, !1)) - }, page.show = function(path, state, dispatch, push, isBack) { + return (page.len || 0) > 0; + }; + + /** + * Register route to redirect from one path to other + * or just redirect to another route + * + * @param {String} from - if param 'to' is undefined redirects to 'from' + * @param {String} [to] + * @api public + */ + page.redirect = function (from, to) { + // Define route from a path to another + if ('string' === typeof from && 'string' === typeof to) { + page(from, function (e) { + setTimeout(function () { + page.replace(to); + }, 0); + }); + } + + // Wait for the push state and replace it with another + if ('string' === typeof from && 'undefined' === typeof to) { + setTimeout(function () { + page.replace(from); + }, 0); + } + }; + + /** + * Replace `path` with optional `state` object. + * + * @param {String} path + * @param {Object} state + * @return {Context} + * @api public + */ + + + page.replace = function (path, state, init, dispatch, isBack) { var ctx = new Context(path, state); - return ctx.isBack = isBack, page.current = ctx.path, !1 !== dispatch && page.dispatch(ctx), !1 !== ctx.handled && !1 !== push && ctx.pushState(), ctx - }, page.restorePreviousState = function() { - prevContext = prevPageContext, page.show(prevContext.pathname, prevContext.state, !1, !0, !1) - }, page.back = function(path, state) { - if (enableHistory) return void history.back(); - if (page.len > 0) { - if (enableHistory) history.back(); - else if (backStack.length > 2) { - backStack.length--; - var previousState = backStack[backStack.length - 1]; - page.show(previousState.path, previousState.state, !0, !1, !0) - } - page.len-- - } else path ? setTimeout(function() { - page.show(path, state) - }) : setTimeout(function() { - page.show(base, state) - }) - }, page.enableNativeHistory = function() { - return enableHistory - }, page.canGoBack = function() { - return enableHistory ? history.length > 1 : (page.len || 0) > 0 - }, page.redirect = function(from, to) { - "string" == typeof from && "string" == typeof to && page(from, function(e) { - setTimeout(function() { - page.replace(to) - }, 0) - }), "string" == typeof from && void 0 === to && setTimeout(function() { - page.replace(from) - }, 0) - }, page.replace = function(path, state, init, dispatch, isBack) { - var ctx = new Context(path, state); - return ctx.isBack = isBack, page.current = ctx.path, ctx.init = init, ctx.save(), !1 !== dispatch && page.dispatch(ctx), ctx - }, page.dispatch = function(ctx) { + ctx.isBack = isBack; + page.current = ctx.path; + ctx.init = init; + ctx.save(); // save before dispatching, which may redirect + if (false !== dispatch) { + page.dispatch(ctx); + } + return ctx; + }; + + /** + * Dispatch the given `ctx`. + * + * @param {Object} ctx + * @api private + */ + + page.dispatch = function (ctx) { + var prev = prevContext, + i = 0, + j = 0; + + prevPageContext = prevContext; + prevContext = ctx; + function nextExit() { var fn = page.exits[j++]; - if (!fn) return nextEnter(); - fn(prev, nextExit) + if (!fn) { + return nextEnter(); + } + fn(prev, nextExit); } function nextEnter() { var fn = page.callbacks[i++]; - return ctx.path !== page.current ? void(ctx.handled = !1) : fn ? void fn(ctx, nextEnter) : unhandled(ctx) + + if (ctx.path !== page.current) { + ctx.handled = false; + return; + } + if (!fn) { + return unhandled(ctx); + } + fn(ctx, nextEnter); } - var prev = prevContext, - i = 0, - j = 0; - prevPageContext = prevContext, prevContext = ctx, prev ? nextExit() : nextEnter() - }, page.exit = function(path, fn) { - if ("function" == typeof path) return page.exit("*", path); - for (var route = new Route(path), i = 1; i < arguments.length; ++i) page.exits.push(route.middleware(arguments[i])) - }, page.Context = Context; + + if (prev) { + nextExit(); + } else { + nextEnter(); + } + }; + + /** + * Unhandled `ctx`. When it's not the initial + * popstate then redirect. If you wish to handle + * 404s on your own use `page('*', callback)`. + * + * @param {Context} ctx + * @api private + */ + + function unhandled(ctx) { + if (ctx.handled) { + return; + } + var current; + + if (hashbang) { + current = base + location.hash.replace('#!', ''); + } else { + current = location.pathname + location.search; + } + + if (current === ctx.canonicalPath) { + return; + } + page.stop(); + ctx.handled = false; + location.href = ctx.canonicalPath; + } + + /** + * Register an exit route on `path` with + * callback `fn()`, which will be called + * on the previous context when a new + * page is visited. + */ + page.exit = function (path, fn) { + if (typeof path === 'function') { + return page.exit('*', path); + } + + var route = new Route(path); + for (var i = 1; i < arguments.length; ++i) { + page.exits.push(route.middleware(arguments[i])); + } + }; + + /** + * Remove URL encoding from the given `str`. + * Accommodates whitespace in both x-www-form-urlencoded + * and regular percent-encoded form. + * + * @param {str} URL component to decode + */ + function decodeURLEncodedURIComponent(val) { + if (typeof val !== 'string') { return val; } + return decodeURLComponents ? decodeURIComponent(val.replace(/\+/g, ' ')) : val; + } + + /** + * Initialize a new "request" `Context` + * with the given `path` and optional initial `state`. + * + * @param {String} path + * @param {Object} state + * @api public + */ + + function Context(path, state) { + if ('/' === path[0] && 0 !== path.indexOf(base)) { + path = base + (hashbang ? '#!' : '') + path; + } + var i = path.indexOf('?'); + + this.canonicalPath = path; + this.path = path.replace(base, '') || '/'; + if (hashbang) { + this.path = this.path.replace('#!', '') || '/'; + } + + this.title = document.title; + this.state = state || {}; + this.state.path = path; + this.querystring = ~i ? decodeURLEncodedURIComponent(path.slice(i + 1)) : ''; + this.pathname = decodeURLEncodedURIComponent(~i ? path.slice(0, i) : path); + this.params = {}; + + // fragment + this.hash = ''; + if (!hashbang) { + if (!~this.path.indexOf('#')) { + return; + } + var parts = this.path.split('#'); + this.path = parts[0]; + this.hash = decodeURLEncodedURIComponent(parts[1]) || ''; + this.querystring = this.querystring.split('#')[0]; + } + } + + /** + * Expose `Context`. + */ + + page.Context = Context; var backStack = []; - Context.prototype.pushState = function() { - page.len++, enableHistory ? history.pushState(this.state, this.title, hashbang && "/" !== this.path ? "#!" + this.path : this.canonicalPath) : backStack.push({ - state: this.state, - title: this.title, - url: hashbang && "/" !== this.path ? "#!" + this.path : this.canonicalPath, - path: this.path - }) - }, Context.prototype.save = function() { - enableHistory ? history.replaceState(this.state, this.title, hashbang && "/" !== this.path ? "#!" + this.path : this.canonicalPath) : backStack[page.len || 0] = { - state: this.state, - title: this.title, - url: hashbang && "/" !== this.path ? "#!" + this.path : this.canonicalPath, - path: this.path + + /** + * Push state. + * + * @api private + */ + + Context.prototype.pushState = function () { + page.len++; + + if (enableHistory) { + history.pushState(this.state, this.title, hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath); + } else { + backStack.push({ + state: this.state, + title: this.title, + url: (hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath), + path: this.path + }); } - }, page.Route = Route, Route.prototype.middleware = function(fn) { + }; + + /** + * Save the context state. + * + * @api public + */ + + Context.prototype.save = function () { + + if (enableHistory) { + history.replaceState(this.state, this.title, hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath); + } else { + backStack[page.len || 0] = { + state: this.state, + title: this.title, + url: (hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath), + path: this.path + }; + } + }; + + /** + * Initialize `Route` with the given HTTP `path`, + * and an array of `callbacks` and `options`. + * + * Options: + * + * - `sensitive` enable case-sensitive routes + * - `strict` enable strict matching for trailing slashes + * + * @param {String} path + * @param {Object} options. + * @api private + */ + + function Route(path, options) { + options = options || {}; + this.path = (path === '*') ? '(.*)' : path; + this.method = 'GET'; + this.regexp = pathToRegexp(this.path, + this.keys = [], + options.sensitive, + options.strict); + } + + /** + * Expose `Route`. + */ + + page.Route = Route; + + /** + * Return route middleware with + * the given callback `fn()`. + * + * @param {Function} fn + * @return {Function} + * @api public + */ + + Route.prototype.middleware = function (fn) { var self = this; - return function(ctx, next) { - if (self.match(ctx.path, ctx.params)) return fn(ctx, next); - next() - } - }, Route.prototype.match = function(path, params) { + return function (ctx, next) { + if (self.match(ctx.path, ctx.params)) { + return fn(ctx, next); + } + next(); + }; + }; + + /** + * Check if this route matches `path`, if so + * populate `params`. + * + * @param {String} path + * @param {Object} params + * @return {Boolean} + * @api private + */ + + Route.prototype.match = function (path, params) { var keys = this.keys, - qsIndex = path.indexOf("?"), + qsIndex = path.indexOf('?'), pathname = ~qsIndex ? path.slice(0, qsIndex) : path, m = this.regexp.exec(decodeURIComponent(pathname)); - if (!m) return !1; - for (var i = 1, len = m.length; i < len; ++i) { - var key = keys[i - 1], - val = decodeURLEncodedURIComponent(m[i]); - void 0 === val && hasOwnProperty.call(params, key.name) || (params[key.name] = val) + + if (!m) { + return false; } - return !0 - }; - var previousPopState = {}; - page.pushState = function(state, title, url) { - hashbang && (url = "#!" + url), history.pushState(state, title, url), previousPopState = state - }; - var onpopstate = function() { - var loaded = !1; - if ("undefined" != typeof window) return "complete" === document.readyState ? loaded = !0 : window.addEventListener("load", function() { - setTimeout(function() { - loaded = !0 - }, 0) - }), - function(e) { - if (loaded && !ignorePopState(e)) - if (e.state) { - var path = e.state.path; - page.replace(path, e.state, null, null, !0) - } else page.show(location.pathname + location.hash, void 0, void 0, !1, !0) + + for (var i = 1, len = m.length; i < len; ++i) { + var key = keys[i - 1]; + var val = decodeURLEncodedURIComponent(m[i]); + if (val !== undefined || !(hasOwnProperty.call(params, key.name))) { + params[key.name] = val; + } + } + + return true; + }; + + + var previousPopState = {}; + + function ignorePopState(event) { + + var state = event.state || {}; + + if (previousPopState.navigate === false) { + // Ignore + previousPopState = state; + return true; + } + + previousPopState = state; + return false; + } + + page.pushState = function (state, title, url) { + + if (hashbang) { + url = '#!' + url; + } + + history.pushState(state, title, url); + previousPopState = state; + }; + + /** + * Handle "populate" events. + */ + + var onpopstate = (function () { + var loaded = false; + if ('undefined' === typeof window) { + return; + } + if (document.readyState === 'complete') { + loaded = true; + } else { + window.addEventListener('load', function () { + setTimeout(function () { + loaded = true; + }, 0); + }); + } + return function onpopstate(e) { + if (!loaded) { + return; + } + if (ignorePopState(e)) { + return; + } + if (e.state) { + var path = e.state.path; + page.replace(path, e.state, null, null, true); + } else { + page.show(location.pathname + location.hash, undefined, undefined, false, true); } - }(); - page.handleAnchorClick = onclick, page.sameOrigin = sameOrigin; - var PATH_REGEXP = new RegExp(["(\\\\.)", "([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^()])+)\\))?|\\(((?:\\\\.|[^()])+)\\))([+*?])?|(\\*))"].join("|"), "g"), - isarray = Array.isArray || function(arr) { - return "[object Array]" === Object.prototype.toString.call(arr) }; - return page + })(); + /** + * Handle "click" events. + */ + + function onclick(e, checkWhich) { + + if (1 !== which(e) && checkWhich !== false) { + return; + } + + if (e.metaKey || e.ctrlKey || e.shiftKey) { + return; + } + if (e.defaultPrevented) { + return; + } + + + // ensure link + var el = e.target; + + while (el && 'A' !== el.nodeName) { + el = el.parentNode; + } + if (!el || 'A' !== el.nodeName) { + return; + } + + + // Ignore if tag has + // 1. "download" attribute + // 2. rel="external" attribute + if (el.hasAttribute('download') || el.getAttribute('rel') === 'external') { + return; + } + + // ensure non-hash for the same path + var link = el.getAttribute('href'); + if (link === '#') { + e.preventDefault(); + return; + } + + if (!hashbang && el.pathname === location.pathname && (el.hash || '#' === link)) { + return; + } + + // check target + if (el.target) { + return; + } + + // x-origin + if (!sameOrigin(el.href)) { + return; + } + + // rebuild path + var path = el.pathname + el.search + (el.hash || ''); + + // same page + var orig = path; + + if (path.indexOf(base) === 0) { + path = path.substr(base.length); + } + + if (hashbang) { + path = path.replace('#!', ''); + } + + if (base && orig === path) { + // This is causing navigation to be canceled in edge uwp + // If needed this can be changed to only be skipped when called via handleAnchorClick + //return; + } + + e.preventDefault(); + page.show(orig); + } + + page.handleAnchorClick = onclick; + + /** + * Event button. + */ + + function which(e) { + e = e || window.event; + return null === e.which ? e.button : e.which; + } + + /** + * Check if `href` is the same origin. + */ + + function sameOrigin(href) { + var origin = location.protocol + '//' + location.hostname; + if (location.port) { + origin += ':' + location.port; + } + return (href && (0 === href.indexOf(origin))); + } + + page.sameOrigin = sameOrigin; + + /** + * The main path matching regexp utility. + * + * @type {RegExp} + */ + var PATH_REGEXP = new RegExp([ + // Match escaped characters that would otherwise appear in future matches. + // This allows the user to escape special characters that won't transform. + '(\\\\.)', + // Match Express-style parameters and un-named parameters with a prefix + // and optional suffixes. Matches appear as: + // + // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined] + // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined] + // "/*" => ["/", undefined, undefined, undefined, undefined, "*"] + '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^()])+)\\))?|\\(((?:\\\\.|[^()])+)\\))([+*?])?|(\\*))' + ].join('|'), 'g'); + + /** + * Parse a string for the raw tokens. + * + * @param {String} str + * @return {Array} + */ + function parse(str) { + var tokens = []; + var key = 0; + var index = 0; + var path = ''; + var res; + + while ((res = PATH_REGEXP.exec(str)) != null) { + var m = res[0]; + var escaped = res[1]; + var offset = res.index; + path += str.slice(index, offset); + index = offset + m.length; + + // Ignore already escaped sequences. + if (escaped) { + path += escaped[1]; + continue; + } + + // Push the current path onto the tokens. + if (path) { + tokens.push(path); + path = ''; + } + + var prefix = res[2]; + var name = res[3]; + var capture = res[4]; + var group = res[5]; + var suffix = res[6]; + var asterisk = res[7]; + + var repeat = suffix === '+' || suffix === '*'; + var optional = suffix === '?' || suffix === '*'; + var delimiter = prefix || '/'; + var pattern = capture || group || (asterisk ? '.*' : '[^' + delimiter + ']+?'); + + tokens.push({ + name: name || key++, + prefix: prefix || '', + delimiter: delimiter, + optional: optional, + repeat: repeat, + pattern: escapeGroup(pattern) + }); + } + + // Match any characters still remaining. + if (index < str.length) { + path += str.substr(index); + } + + // If the path exists, push it onto the end. + if (path) { + tokens.push(path); + } + + return tokens; + } + + var isarray = Array.isArray || function (arr) { + return Object.prototype.toString.call(arr) === '[object Array]'; + }; + + /** + * Escape a regular expression string. + * + * @param {String} str + * @return {String} + */ + function escapeString(str) { + return str.replace(/([.+*?=^!:${}()[\]|\/])/g, '\\$1'); + } + + /** + * Escape the capturing group by escaping special characters and meaning. + * + * @param {String} group + * @return {String} + */ + function escapeGroup(group) { + return group.replace(/([=!:$\/()])/g, '\\$1'); + } + + /** + * Attach the keys as a property of the regexp. + * + * @param {RegExp} re + * @param {Array} keys + * @return {RegExp} + */ + function attachKeys(re, keys) { + re.keys = keys; + return re; + } + + /** + * Get the flags for a regexp from the options. + * + * @param {Object} options + * @return {String} + */ + function flags(options) { + return options.sensitive ? '' : 'i'; + } + + /** + * Pull out keys from a regexp. + * + * @param {RegExp} path + * @param {Array} keys + * @return {RegExp} + */ + function regexpToRegexp(path, keys) { + // Use a negative lookahead to match only capturing groups. + var groups = path.source.match(/\((?!\?)/g); + + if (groups) { + for (var i = 0; i < groups.length; i++) { + keys.push({ + name: i, + prefix: null, + delimiter: null, + optional: false, + repeat: false, + pattern: null + }); + } + } + + return attachKeys(path, keys); + } + + /** + * Transform an array into a regexp. + * + * @param {Array} path + * @param {Array} keys + * @param {Object} options + * @return {RegExp} + */ + function arrayToRegexp(path, keys, options) { + var parts = []; + + for (var i = 0; i < path.length; i++) { + parts.push(pathToRegexp(path[i], keys, options).source); + } + + var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options)); + + return attachKeys(regexp, keys); + } + + /** + * Create a path regexp from string input. + * + * @param {String} path + * @param {Array} keys + * @param {Object} options + * @return {RegExp} + */ + function stringToRegexp(path, keys, options) { + var tokens = parse(path); + var re = tokensToRegExp(tokens, options); + + // Attach keys back to the regexp. + for (var i = 0; i < tokens.length; i++) { + if (typeof tokens[i] !== 'string') { + keys.push(tokens[i]); + } + } + + return attachKeys(re, keys); + } + + /** + * Expose a function for taking tokens and returning a RegExp. + * + * @param {Array} tokens + * @param {Array} keys + * @param {Object} options + * @return {RegExp} + */ + function tokensToRegExp(tokens, options) { + options = options || {}; + + var strict = options.strict; + var end = options.end !== false; + var route = ''; + var lastToken = tokens[tokens.length - 1]; + var endsWithSlash = typeof lastToken === 'string' && /\/$/.test(lastToken); + + // Iterate over the tokens and create our regexp string. + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + + if (typeof token === 'string') { + route += escapeString(token); + } else { + var prefix = escapeString(token.prefix); + var capture = token.pattern; + + if (token.repeat) { + capture += '(?:' + prefix + capture + ')*'; + } + + if (token.optional) { + if (prefix) { + capture = '(?:' + prefix + '(' + capture + '))?'; + } else { + capture = '(' + capture + ')?'; + } + } else { + capture = prefix + '(' + capture + ')'; + } + + route += capture; + } + } + + // In non-strict mode we allow a slash at the end of match. If the path to + // match already ends with a slash, we remove it for consistency. The slash + // is valid at the end of a path match, not in the middle. This is important + // in non-ending mode, where "/test/" shouldn't match "/test//route". + if (!strict) { + route = (endsWithSlash ? route.slice(0, -2) : route) + '(?:\\/(?=$))?'; + } + + if (end) { + route += '$'; + } else { + // In non-ending mode, we need the capturing groups to match as much as + // possible by using a positive lookahead to the end or next path segment. + route += strict && endsWithSlash ? '' : '(?=\\/|$)'; + } + + return new RegExp('^' + route, flags(options)); + } + + /** + * Normalize the given path string, returning a regular expression. + * + * An empty array can be passed in for the keys, which will hold the + * placeholder key descriptions. For example, using `/user/:id`, `keys` will + * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`. + * + * @param {(String|RegExp|Array)} path + * @param {Array} [keys] + * @param {Object} [options] + * @return {RegExp} + */ + function pathToRegexp(path, keys, options) { + keys = keys || []; + + if (!isarray(keys)) { + options = keys; + keys = []; + } else if (!options) { + options = {}; + } + + if (path instanceof RegExp) { + return regexpToRegexp(path, keys, options); + } + + if (isarray(path)) { + return arrayToRegexp(path, keys, options); + } + + return stringToRegexp(path, keys, options); + } + + return page; + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/photoplayer/plugin.js b/src/bower_components/emby-webcomponents/photoplayer/plugin.js index 137a3520e1..6629fbfb0f 100644 --- a/src/bower_components/emby-webcomponents/photoplayer/plugin.js +++ b/src/bower_components/emby-webcomponents/photoplayer/plugin.js @@ -1,25 +1,46 @@ -define(["browser", "require", "events", "apphost", "loading", "dom", "playbackManager", "appRouter", "appSettings", "connectionManager"], function(browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager) { +define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager) { "use strict"; function PhotoPlayer() { + var self = this; - self.name = "Photo Player", self.type = "mediaplayer", self.id = "photoplayer", self.priority = 1 + + self.name = 'Photo Player'; + self.type = 'mediaplayer'; + self.id = 'photoplayer'; + + // Let any players created by plugins take priority + self.priority = 1; } - return PhotoPlayer.prototype.play = function(options) { - return new Promise(function(resolve, reject) { - require(["slideshow"], function(slideshow) { + + PhotoPlayer.prototype.play = function (options) { + + return new Promise(function (resolve, reject) { + + require(['slideshow'], function (slideshow) { + var index = options.startIndex || 0; - new slideshow({ - showTitle: !1, - cover: !1, + + var newSlideShow = new slideshow({ + showTitle: false, + cover: false, items: options.items, startIndex: index, - interval: 11e3, - interactive: !0 - }).show(), resolve() - }) - }) - }, PhotoPlayer.prototype.canPlayMediaType = function(mediaType) { - return "photo" === (mediaType || "").toLowerCase() - }, PhotoPlayer + interval: 11000, + interactive: true + }); + + newSlideShow.show(); + + resolve(); + }); + }); + }; + + PhotoPlayer.prototype.canPlayMediaType = function (mediaType) { + + return (mediaType || '').toLowerCase() === 'photo'; + }; + + return PhotoPlayer; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/autoplaydetect.js b/src/bower_components/emby-webcomponents/playback/autoplaydetect.js index 63b24cfeeb..7a7a73a538 100644 --- a/src/bower_components/emby-webcomponents/playback/autoplaydetect.js +++ b/src/bower_components/emby-webcomponents/playback/autoplaydetect.js @@ -1,28 +1,63 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; function supportsHtmlMediaAutoplay() { - return new Promise(function(resolve, reject) { - var timeout, elem = document.createElement("video"), - elemStyle = elem.style; - if (!("autoplay" in elem)) return void reject(); - elemStyle.position = "absolute", elemStyle.height = 0, elemStyle.width = 0, elem.setAttribute("autoplay", "autoplay"), elem.style.display = "none", document.body.appendChild(elem); - var testAutoplay = function(arg) { - clearTimeout(timeout), elem.removeEventListener("playing", testAutoplay), elem.removeEventListener("play", testAutoplay); - var supported = arg && "playing" === arg.type || arg && "play" === arg.type || 0 !== elem.currentTime; - elem.parentNode.removeChild(elem), supported ? resolve() : reject() - }; - elem.addEventListener("play", testAutoplay), elem.addEventListener("playing", testAutoplay); - try { - elem.src = "data:video/mp4;base64,AAAAHGZ0eXBtcDQyAAAAAG1wNDJpc29tYXZjMQAAAz5tb292AAAAbG12aGQAAAAAzaNacc2jWnEAAV+QAAFfkAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAGGlvZHMAAAAAEICAgAcAT////3//AAACQ3RyYWsAAABcdGtoZAAAAAHNo1pxzaNacQAAAAEAAAAAAAFfkAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAEAAAABAAAAAAAd9tZGlhAAAAIG1kaGQAAAAAzaNacc2jWnEAAV+QAAFfkFXEAAAAAAAhaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAAAAAAGWbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABVnN0YmwAAACpc3RzZAAAAAAAAAABAAAAmWF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAEAAQAEgAAABIAAAAAAAAAAEOSlZUL0FWQyBDb2RpbmcAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwH0AAr/4QAZZ/QACq609NQYBBkAAAMAAQAAAwAKjxImoAEABWjOAa8gAAAAEmNvbHJuY2xjAAYAAQAGAAAAGHN0dHMAAAAAAAAAAQAAAAUAAEZQAAAAKHN0c3oAAAAAAAAAAAAAAAUAAAIqAAAACAAAAAgAAAAIAAAACAAAAChzdHNjAAAAAAAAAAIAAAABAAAABAAAAAEAAAACAAAAAQAAAAEAAAAYc3RjbwAAAAAAAAACAAADYgAABaQAAAAUc3RzcwAAAAAAAAABAAAAAQAAABFzZHRwAAAAAAREREREAAAAb3VkdGEAAABnbWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcgAAAAAAAAAAAAAAAAAAAAA6aWxzdAAAADKpdG9vAAAAKmRhdGEAAAABAAAAAEhhbmRCcmFrZSAwLjkuOCAyMDEyMDcxODAwAAACUm1kYXQAAAHkBgX/4NxF6b3m2Ui3lizYINkj7u94MjY0IC0gY29yZSAxMjAgLSBILjI2NC9NUEVHLTQgQVZDIGNvZGVjIC0gQ29weWxlZnQgMjAwMy0yMDExIC0gaHR0cDovL3d3dy52aWRlb2xhbi5vcmcveDI2NC5odG1sIC0gb3B0aW9uczogY2FiYWM9MCByZWY9MSBkZWJsb2NrPTE6MDowIGFuYWx5c2U9MHgxOjAgbWU9ZXNhIHN1Ym1lPTkgcHN5PTAgbWl4ZWRfcmVmPTAgbWVfcmFuZ2U9NCBjaHJvbWFfbWU9MSB0cmVsbGlzPTAgOHg4ZGN0PTAgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0wIGNocm9tYV9xcF9vZmZzZXQ9MCB0aHJlYWRzPTYgc2xpY2VkX3RocmVhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MCB3ZWlnaHRwPTAga2V5aW50PTUwIGtleWludF9taW49NSBzY2VuZWN1dD00MCBpbnRyYV9yZWZyZXNoPTAgcmM9Y3FwIG1idHJlZT0wIHFwPTAAgAAAAD5liISscR8A+E4ACAACFoAAITAAAgsAAPgYCoKgoC+L4vi+KAvi+L4YfAEAACMzgABF9AAEUGUgABDJiXnf4AAAAARBmiKUAAAABEGaQpQAAAAEQZpilAAAAARBmoKU"; - var promise = elem.play(); - promise && promise.catch && promise.catch(reject), timeout = setTimeout(testAutoplay, 500) - } catch (e) { - return void reject() + + return new Promise(function (resolve, reject) { + + var timeout; + var elem = document.createElement('video'); + var elemStyle = elem.style; + //skip the test if video itself, or the autoplay + //element on it isn't supported + if (!('autoplay' in elem)) { + reject(); + return; } - }) + elemStyle.position = 'absolute'; + elemStyle.height = 0; + elemStyle.width = 0; + + elem.setAttribute('autoplay', 'autoplay'); + elem.style.display = 'none'; + document.body.appendChild(elem); + + var testAutoplay = function (arg) { + clearTimeout(timeout); + elem.removeEventListener('playing', testAutoplay); + elem.removeEventListener('play', testAutoplay); + var supported = (arg && arg.type === 'playing') || (arg && arg.type === 'play') || elem.currentTime !== 0; + elem.parentNode.removeChild(elem); + + if (supported) { + resolve(); + } else { + reject(); + } + }; + + // play needed for firefox + elem.addEventListener('play', testAutoplay); + elem.addEventListener('playing', testAutoplay); + + try { + elem.src = 'data:video/mp4;base64,AAAAHGZ0eXBtcDQyAAAAAG1wNDJpc29tYXZjMQAAAz5tb292AAAAbG12aGQAAAAAzaNacc2jWnEAAV+QAAFfkAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAGGlvZHMAAAAAEICAgAcAT////3//AAACQ3RyYWsAAABcdGtoZAAAAAHNo1pxzaNacQAAAAEAAAAAAAFfkAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAEAAAABAAAAAAAd9tZGlhAAAAIG1kaGQAAAAAzaNacc2jWnEAAV+QAAFfkFXEAAAAAAAhaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAAAAAAGWbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABVnN0YmwAAACpc3RzZAAAAAAAAAABAAAAmWF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAEAAQAEgAAABIAAAAAAAAAAEOSlZUL0FWQyBDb2RpbmcAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwH0AAr/4QAZZ/QACq609NQYBBkAAAMAAQAAAwAKjxImoAEABWjOAa8gAAAAEmNvbHJuY2xjAAYAAQAGAAAAGHN0dHMAAAAAAAAAAQAAAAUAAEZQAAAAKHN0c3oAAAAAAAAAAAAAAAUAAAIqAAAACAAAAAgAAAAIAAAACAAAAChzdHNjAAAAAAAAAAIAAAABAAAABAAAAAEAAAACAAAAAQAAAAEAAAAYc3RjbwAAAAAAAAACAAADYgAABaQAAAAUc3RzcwAAAAAAAAABAAAAAQAAABFzZHRwAAAAAAREREREAAAAb3VkdGEAAABnbWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcgAAAAAAAAAAAAAAAAAAAAA6aWxzdAAAADKpdG9vAAAAKmRhdGEAAAABAAAAAEhhbmRCcmFrZSAwLjkuOCAyMDEyMDcxODAwAAACUm1kYXQAAAHkBgX/4NxF6b3m2Ui3lizYINkj7u94MjY0IC0gY29yZSAxMjAgLSBILjI2NC9NUEVHLTQgQVZDIGNvZGVjIC0gQ29weWxlZnQgMjAwMy0yMDExIC0gaHR0cDovL3d3dy52aWRlb2xhbi5vcmcveDI2NC5odG1sIC0gb3B0aW9uczogY2FiYWM9MCByZWY9MSBkZWJsb2NrPTE6MDowIGFuYWx5c2U9MHgxOjAgbWU9ZXNhIHN1Ym1lPTkgcHN5PTAgbWl4ZWRfcmVmPTAgbWVfcmFuZ2U9NCBjaHJvbWFfbWU9MSB0cmVsbGlzPTAgOHg4ZGN0PTAgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0wIGNocm9tYV9xcF9vZmZzZXQ9MCB0aHJlYWRzPTYgc2xpY2VkX3RocmVhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MCB3ZWlnaHRwPTAga2V5aW50PTUwIGtleWludF9taW49NSBzY2VuZWN1dD00MCBpbnRyYV9yZWZyZXNoPTAgcmM9Y3FwIG1idHJlZT0wIHFwPTAAgAAAAD5liISscR8A+E4ACAACFoAAITAAAgsAAPgYCoKgoC+L4vi+KAvi+L4YfAEAACMzgABF9AAEUGUgABDJiXnf4AAAAARBmiKUAAAABEGaQpQAAAAEQZpilAAAAARBmoKU'; + var promise = elem.play(); + if (promise && promise.catch) { + promise.catch(reject); + } + + timeout = setTimeout(testAutoplay, 500); + } + + catch (e) { + reject(); + return; + } + }); } + return { supportsHtmlMediaAutoplay: supportsHtmlMediaAutoplay - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/brightnessosd.js b/src/bower_components/emby-webcomponents/playback/brightnessosd.js index 9b53743217..4885d2e4e1 100644 --- a/src/bower_components/emby-webcomponents/playback/brightnessosd.js +++ b/src/bower_components/emby-webcomponents/playback/brightnessosd.js @@ -1,63 +1,165 @@ -define(["events", "playbackManager", "dom", "browser", "css!./iconosd", "material-icons"], function(events, playbackManager, dom, browser) { - "use strict"; +define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'material-icons'], function (events, playbackManager, dom, browser) { + 'use strict'; + + var currentPlayer; + var osdElement; + var iconElement; + var progressElement; + + var enableAnimation; function getOsdElementHtml() { - var html = ""; - return html += '', html += '
' + var html = ''; + + html += ''; + + html += '
'; + + return html; } function ensureOsdElement() { + var elem = osdElement; - elem || (enableAnimation = browser.supportsCssAnimation(), elem = document.createElement("div"), elem.classList.add("hide"), elem.classList.add("iconOsd"), elem.classList.add("iconOsd-hidden"), elem.classList.add("brightnessOsd"), elem.innerHTML = getOsdElementHtml(), iconElement = elem.querySelector("i"), progressElement = elem.querySelector(".iconOsdProgressInner"), document.body.appendChild(elem), osdElement = elem) + if (!elem) { + + enableAnimation = browser.supportsCssAnimation(); + + elem = document.createElement('div'); + elem.classList.add('hide'); + elem.classList.add('iconOsd'); + elem.classList.add('iconOsd-hidden'); + elem.classList.add('brightnessOsd'); + elem.innerHTML = getOsdElementHtml(); + + iconElement = elem.querySelector('i'); + progressElement = elem.querySelector('.iconOsdProgressInner'); + + document.body.appendChild(elem); + osdElement = elem; + } } function onHideComplete() { - this.classList.add("hide") + this.classList.add('hide'); } + var hideTimeout; function showOsd() { + clearHideTimeout(); + var elem = osdElement; + dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { - once: !0 - }), elem.classList.remove("hide"), elem.offsetWidth, requestAnimationFrame(function() { - elem.classList.remove("iconOsd-hidden"), hideTimeout = setTimeout(hideOsd, 3e3) - }) + once: true + }); + + elem.classList.remove('hide'); + + // trigger reflow + void elem.offsetWidth; + + requestAnimationFrame(function () { + elem.classList.remove('iconOsd-hidden'); + + hideTimeout = setTimeout(hideOsd, 3000); + }); } function clearHideTimeout() { - hideTimeout && (clearTimeout(hideTimeout), hideTimeout = null) + if (hideTimeout) { + clearTimeout(hideTimeout); + hideTimeout = null; + } } function hideOsd() { + clearHideTimeout(); + var elem = osdElement; - elem && (enableAnimation ? (elem.offsetWidth, requestAnimationFrame(function() { - elem.classList.add("iconOsd-hidden"), dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { - once: !0 - }) - })) : onHideComplete.call(elem)) + if (elem) { + + if (enableAnimation) { + // trigger reflow + void elem.offsetWidth; + + requestAnimationFrame(function () { + elem.classList.add('iconOsd-hidden'); + + dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { + once: true + }); + }); + } else { + onHideComplete.call(elem); + } + } } function updateElementsFromPlayer(brightness) { - iconElement && (iconElement.innerHTML = brightness >= 80 ? "" : brightness >= 20 ? "" : ""), progressElement && (progressElement.style.width = (brightness || 0) + "%") + + if (iconElement) { + if (brightness >= 80) { + iconElement.innerHTML = ''; + } + else if (brightness >= 20) { + iconElement.innerHTML = ''; + } else { + iconElement.innerHTML = ''; + } + } + if (progressElement) { + progressElement.style.width = (brightness || 0) + '%'; + } } function releaseCurrentPlayer() { + var player = currentPlayer; - player && (events.off(player, "brightnesschange", onBrightnessChanged), events.off(player, "playbackstop", hideOsd), currentPlayer = null) + + if (player) { + events.off(player, 'brightnesschange', onBrightnessChanged); + events.off(player, 'playbackstop', hideOsd); + currentPlayer = null; + } } function onBrightnessChanged(e) { + var player = this; - ensureOsdElement(), updateElementsFromPlayer(playbackManager.getBrightness(player)), showOsd() + + ensureOsdElement(); + + updateElementsFromPlayer(playbackManager.getBrightness(player)); + + showOsd(); } function bindToPlayer(player) { - player !== currentPlayer && (releaseCurrentPlayer(), currentPlayer = player, player && (hideOsd(), events.on(player, "brightnesschange", onBrightnessChanged), events.on(player, "playbackstop", hideOsd))) + + if (player === currentPlayer) { + return; + } + + releaseCurrentPlayer(); + + currentPlayer = player; + + if (!player) { + return; + } + + hideOsd(); + events.on(player, 'brightnesschange', onBrightnessChanged); + events.on(player, 'playbackstop', hideOsd); } - var currentPlayer, osdElement, iconElement, progressElement, enableAnimation, hideTimeout; - events.on(playbackManager, "playerchange", function() { - bindToPlayer(playbackManager.getCurrentPlayer()) - }), bindToPlayer(playbackManager.getCurrentPlayer()) + + events.on(playbackManager, 'playerchange', function () { + bindToPlayer(playbackManager.getCurrentPlayer()); + }); + + bindToPlayer(playbackManager.getCurrentPlayer()); + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/experimentalwarnings.js b/src/bower_components/emby-webcomponents/playback/experimentalwarnings.js index dd43fe47db..2b6c5d10ae 100644 --- a/src/bower_components/emby-webcomponents/playback/experimentalwarnings.js +++ b/src/bower_components/emby-webcomponents/playback/experimentalwarnings.js @@ -1,41 +1,97 @@ -define(["connectionManager", "globalize", "userSettings", "apphost"], function(connectionManager, globalize, userSettings, appHost) { +define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function (connectionManager, globalize, userSettings, appHost) { "use strict"; + function getRequirePromise(deps) { + + return new Promise(function (resolve, reject) { + + require(deps, resolve); + }); + } + + // https://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php function getWeek(date) { - var d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())), - dayNum = d.getUTCDay() || 7; + var d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())); + var dayNum = d.getUTCDay() || 7; d.setUTCDate(d.getUTCDate() + 4 - dayNum); var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1)); - return Math.ceil(((d - yearStart) / 864e5 + 1) / 7) + return Math.ceil((((d - yearStart) / 86400000) + 1) / 7); } function showMessage(text, userSettingsKey, appHostFeature) { - if (appHost.supports(appHostFeature)) return Promise.resolve(); - var now = new Date; - return userSettingsKey += now.getFullYear() + "-w" + getWeek(now), "1" === userSettings.get(userSettingsKey, !1) ? Promise.resolve() : new Promise(function(resolve, reject) { - userSettings.set(userSettingsKey, "1", !1), require(["alert"], function(alert) { - return alert(text).then(resolve, resolve) - }) - }) + + if (appHost.supports(appHostFeature)) { + return Promise.resolve(); + } + + var now = new Date(); + + userSettingsKey += now.getFullYear() + '-w' + getWeek(now); + + if (userSettings.get(userSettingsKey, false) === '1') { + return Promise.resolve(); + } + + return new Promise(function (resolve, reject) { + + userSettings.set(userSettingsKey, '1', false); + + require(['alert'], function (alert) { + + return alert(text).then(resolve, resolve); + }); + }); } function showBlurayMessage() { - return showMessage("Playback of Bluray folders in this app is experimental. Some titles may not work at all. For a better experience, consider converting to mkv video files, or use an Jellyfin app with native Bluray folder support.", "blurayexpirementalinfo", "nativeblurayplayback") + + var message = + 'Playback of Bluray folders in this app is experimental. Some titles may not work at all. For a better experience, consider converting to mkv video files, or use an Emby app with native Bluray folder support.'; + return showMessage(message, 'blurayexpirementalinfo', 'nativeblurayplayback'); } function showDvdMessage() { - return showMessage("Playback of Dvd folders in this app is experimental. Some titles may not work at all. For a better experience, consider converting to mkv video files, or use an Jellyfin app with native Dvd folder support.", "dvdexpirementalinfo", "nativedvdplayback") + + var message = + 'Playback of Dvd folders in this app is experimental. Some titles may not work at all. For a better experience, consider converting to mkv video files, or use an Emby app with native Dvd folder support.'; + return showMessage(message, 'dvdexpirementalinfo', 'nativedvdplayback'); } function showIsoMessage() { - return showMessage("Playback of ISO files in this app is experimental. Some titles may not work at all. For a better experience, consider converting to mkv video files, or use an Jellyfin app with native ISO support.", "isoexpirementalinfo", "nativeisoplayback") + + var message = + 'Playback of ISO files in this app is experimental. Some titles may not work at all. For a better experience, consider converting to mkv video files, or use an Emby app with native ISO support.'; + return showMessage(message, 'isoexpirementalinfo', 'nativeisoplayback'); } function ExpirementalPlaybackWarnings() { - this.name = "Experimental playback warnings", this.type = "preplayintercept", this.id = "expirementalplaybackwarnings" + + this.name = 'Experimental playback warnings'; + this.type = 'preplayintercept'; + this.id = 'expirementalplaybackwarnings'; } - return ExpirementalPlaybackWarnings.prototype.intercept = function(options) { + + ExpirementalPlaybackWarnings.prototype.intercept = function (options) { + var item = options.item; - return item ? "Iso" === item.VideoType ? showIsoMessage() : "BluRay" === item.VideoType ? showBlurayMessage() : "Dvd" === item.VideoType ? showDvdMessage() : Promise.resolve() : Promise.resolve() - }, ExpirementalPlaybackWarnings -}); + if (!item) { + return Promise.resolve(); + } + + if (item.VideoType === 'Iso') { + return showIsoMessage(); + } + + if (item.VideoType === 'BluRay') { + return showBlurayMessage(); + } + + if (item.VideoType === 'Dvd') { + return showDvdMessage(); + } + + return Promise.resolve(); + }; + + return ExpirementalPlaybackWarnings; +}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/iconosd.css b/src/bower_components/emby-webcomponents/playback/iconosd.css index d3034a6abe..b5c7ed01bc 100644 --- a/src/bower_components/emby-webcomponents/playback/iconosd.css +++ b/src/bower_components/emby-webcomponents/playback/iconosd.css @@ -1,4 +1,4 @@ -.iconOsd { +.iconOsd { position: fixed; top: 7%; right: 3%; @@ -8,38 +8,33 @@ padding: 1em; color: #fff; backdrop-filter: blur(5px); - -webkit-border-radius: .25em; border-radius: .25em; - -webkit-transition: opacity .2s ease-out; - -o-transition: opacity .2s ease-out; - transition: opacity .2s ease-out + transition: opacity 200ms ease-out; } .iconOsd-hidden { - opacity: 0 + opacity: 0; } .iconOsdIcon { font-size: 320%; display: block; - margin: .25em .7em + margin: .25em .7em; } .iconOsdProgressOuter { margin: 1.5em .25em 1em; height: .35em; background: #222; - -webkit-border-radius: .25em; - border-radius: .25em + border-radius: .25em; } .iconOsdProgressInner { - background: #00a4dc; + background: #52B54B; height: 100%; - -webkit-border-radius: .25em; - border-radius: .25em + border-radius: .25em; } .brightnessOsdProgressInner { - background: #FF9800 -} \ No newline at end of file + background: #FF9800; +} diff --git a/src/bower_components/emby-webcomponents/playback/mediasession.js b/src/bower_components/emby-webcomponents/playback/mediasession.js index 15c6f9cc23..8198a95520 100644 --- a/src/bower_components/emby-webcomponents/playback/mediasession.js +++ b/src/bower_components/emby-webcomponents/playback/mediasession.js @@ -1,54 +1,136 @@ -define(["playbackManager", "nowPlayingHelper", "events", "connectionManager"], function(playbackManager, nowPlayingHelper, events, connectionManager) { +define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], function (playbackManager, nowPlayingHelper, events, connectionManager) { "use strict"; + // Reports media playback to the device for lock screen control + + var currentPlayer; + var lastUpdateTime = 0; + function seriesImageUrl(item, options) { - if ("Episode" !== item.Type) return null; - if (options = options || {}, options.type = options.type || "Primary", "Primary" === options.type && item.SeriesPrimaryImageTag) return options.tag = item.SeriesPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - if ("Thumb" === options.type) { - if (item.SeriesThumbImageTag) return options.tag = item.SeriesThumbImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - if (item.ParentThumbImageTag) return options.tag = item.ParentThumbImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options) + + if (item.Type !== 'Episode') { + return null; } - return null + + options = options || {}; + options.type = options.type || "Primary"; + + if (options.type === 'Primary') { + + if (item.SeriesPrimaryImageTag) { + + options.tag = item.SeriesPrimaryImageTag; + + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + } + } + + if (options.type === 'Thumb') { + + if (item.SeriesThumbImageTag) { + + options.tag = item.SeriesThumbImageTag; + + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + } + if (item.ParentThumbImageTag) { + + options.tag = item.ParentThumbImageTag; + + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options); + } + } + + return null; } function imageUrl(item, options) { - return options = options || {}, options.type = options.type || "Primary", item.ImageTags && item.ImageTags[options.type] ? (options.tag = item.ImageTags[options.type], connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.Id, options)) : item.AlbumId && item.AlbumPrimaryImageTag ? (options.tag = item.AlbumPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options)) : null + + options = options || {}; + options.type = options.type || "Primary"; + + if (item.ImageTags && item.ImageTags[options.type]) { + + options.tag = item.ImageTags[options.type]; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.Id, options); + } + + if (item.AlbumId && item.AlbumPrimaryImageTag) { + + options.tag = item.AlbumPrimaryImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options); + } + + return null; } function pushImageUrl(item, height, list) { + var imageOptions = { - height: height - }, - url = seriesImageUrl(item, imageOptions) || imageUrl(item, imageOptions); - url && list.push({ - src: url, - sizes: height + "x" + height - }) + height: height + }; + + var url = seriesImageUrl(item, imageOptions) || imageUrl(item, imageOptions); + if (url) { + list.push({ src: url, sizes: height + 'x' + height }); + } } function getImageUrls(item) { + var list = []; - return pushImageUrl(item, 96, list), pushImageUrl(item, 128, list), pushImageUrl(item, 192, list), pushImageUrl(item, 256, list), pushImageUrl(item, 384, list), pushImageUrl(item, 512, list), list + + pushImageUrl(item, 96, list); + pushImageUrl(item, 128, list); + pushImageUrl(item, 192, list); + pushImageUrl(item, 256, list); + pushImageUrl(item, 384, list); + pushImageUrl(item, 512, list); + + return list; } function updatePlayerState(player, state, eventName) { + var item = state.NowPlayingItem; - if (!item) return void hideMediaControls(); - var playState = state.PlayState || {}, - parts = nowPlayingHelper.getNowPlayingNames(item), - artist = 1 === parts.length ? "" : parts[0].text, - title = parts[parts.length - 1].text; - if ("Video" === item.MediaType && parts.length > 1) { - var temp = artist; - artist = title, title = temp + + if (!item) { + hideMediaControls(); + return; } + + var playState = state.PlayState || {}; + + var parts = nowPlayingHelper.getNowPlayingNames(item); + + var artist = parts.length === 1 ? '' : parts[0].text; + var title = parts[parts.length - 1].text; + + var isVideo = item.MediaType === 'Video'; + + // Switch these two around for video + if (isVideo && parts.length > 1) { + var temp = artist; + artist = title; + title = temp; + } + var albumArtist; - item.AlbumArtists && item.AlbumArtists[0] && (albumArtist = item.AlbumArtists[0].Name); - var album = item.Album || "", - itemId = item.Id, - duration = parseInt(item.RunTimeTicks ? item.RunTimeTicks / 1e4 : 0), - currentTime = parseInt(playState.PositionTicks ? playState.PositionTicks / 1e4 : 0), - isPaused = playState.IsPaused || !1; + + if (item.AlbumArtists && item.AlbumArtists[0]) { + albumArtist = item.AlbumArtists[0].Name; + } + + var album = item.Album || ''; + var itemId = item.Id; + + // Convert to ms + var duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0); + var currentTime = parseInt(playState.PositionTicks ? (playState.PositionTicks / 10000) : 0); + + var isPaused = playState.IsPaused || false; + var canSeek = playState.CanSeek || false; + navigator.mediaSession.metadata = new MediaMetadata({ title: title, artist: artist, @@ -60,58 +142,111 @@ define(["playbackManager", "nowPlayingHelper", "events", "connectionManager"], f paused: isPaused, itemId: itemId, mediaType: item.MediaType - }) + }); } function onGeneralEvent(e) { + var player = this; - updatePlayerState(player, playbackManager.getPlayerState(player), e.type) + var state = playbackManager.getPlayerState(player); + + updatePlayerState(player, state, e.type); } function onStateChanged(e, state) { - updatePlayerState(this, state, "statechange") + + var player = this; + updatePlayerState(player, state, 'statechange'); } function onPlaybackStart(e, state) { - updatePlayerState(this, state, e.type) + + var player = this; + + updatePlayerState(player, state, e.type); } function onPlaybackStopped(e, state) { - hideMediaControls() + + var player = this; + + hideMediaControls(); } function releaseCurrentPlayer() { - currentPlayer && (events.off(currentPlayer, "playbackstart", onPlaybackStart), events.off(currentPlayer, "playbackstop", onPlaybackStopped), events.off(currentPlayer, "unpause", onGeneralEvent), events.off(currentPlayer, "pause", onGeneralEvent), events.off(currentPlayer, "statechange", onStateChanged), events.off(currentPlayer, "timeupdate", onGeneralEvent), currentPlayer = null, hideMediaControls()) - } - function hideMediaControls() { - navigator.mediaSession.metadata = null - } + if (currentPlayer) { - function bindToPlayer(player) { - if (releaseCurrentPlayer(), player) { - currentPlayer = player; - updatePlayerState(player, playbackManager.getPlayerState(player), "init"), events.on(currentPlayer, "playbackstart", onPlaybackStart), events.on(currentPlayer, "playbackstop", onPlaybackStopped), events.on(currentPlayer, "unpause", onGeneralEvent), events.on(currentPlayer, "pause", onGeneralEvent), events.on(currentPlayer, "statechange", onStateChanged), events.on(currentPlayer, "timeupdate", onGeneralEvent) + events.off(currentPlayer, 'playbackstart', onPlaybackStart); + events.off(currentPlayer, 'playbackstop', onPlaybackStopped); + events.off(currentPlayer, 'unpause', onGeneralEvent); + events.off(currentPlayer, 'pause', onGeneralEvent); + events.off(currentPlayer, 'statechange', onStateChanged); + events.off(currentPlayer, 'timeupdate', onGeneralEvent); + + currentPlayer = null; + + hideMediaControls(); } } - function execute(name) { - playbackManager[name](currentPlayer) + function hideMediaControls() { + navigator.mediaSession.metadata = null; } - var currentPlayer; - navigator.mediaSession.setActionHandler("previoustrack", function() { - execute("previousTrack") - }), navigator.mediaSession.setActionHandler("nexttrack", function() { - execute("nextTrack") - }), navigator.mediaSession.setActionHandler("play", function() { - execute("unpause") - }), navigator.mediaSession.setActionHandler("pause", function() { - execute("pause") - }), navigator.mediaSession.setActionHandler("seekbackward", function() { - execute("rewind") - }), navigator.mediaSession.setActionHandler("seekforward", function() { - execute("fastForward") - }), events.on(playbackManager, "playerchange", function() { - bindToPlayer(playbackManager.getCurrentPlayer()) - }), bindToPlayer(playbackManager.getCurrentPlayer()) + + function bindToPlayer(player) { + + releaseCurrentPlayer(); + + if (!player) { + return; + } + + currentPlayer = player; + + var state = playbackManager.getPlayerState(player); + updatePlayerState(player, state, 'init'); + + events.on(currentPlayer, 'playbackstart', onPlaybackStart); + events.on(currentPlayer, 'playbackstop', onPlaybackStopped); + events.on(currentPlayer, 'unpause', onGeneralEvent); + events.on(currentPlayer, 'pause', onGeneralEvent); + events.on(currentPlayer, 'statechange', onStateChanged); + events.on(currentPlayer, 'timeupdate', onGeneralEvent); + } + + function execute(name) { + playbackManager[name](currentPlayer); + } + + navigator.mediaSession.setActionHandler('previoustrack', function () { + execute('previousTrack'); + }); + + navigator.mediaSession.setActionHandler('nexttrack', function () { + execute('nextTrack'); + }); + + navigator.mediaSession.setActionHandler('play', function () { + execute('unpause'); + }); + + navigator.mediaSession.setActionHandler('pause', function () { + execute('pause'); + }); + + navigator.mediaSession.setActionHandler('seekbackward', function () { + execute('rewind'); + }); + + navigator.mediaSession.setActionHandler('seekforward', function () { + execute('fastForward'); + }); + + events.on(playbackManager, 'playerchange', function () { + + bindToPlayer(playbackManager.getCurrentPlayer()); + }); + + bindToPlayer(playbackManager.getCurrentPlayer()); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/nowplayinghelper.js b/src/bower_components/emby-webcomponents/playback/nowplayinghelper.js index 0e79788291..d5803b426f 100644 --- a/src/bower_components/emby-webcomponents/playback/nowplayinghelper.js +++ b/src/bower_components/emby-webcomponents/playback/nowplayinghelper.js @@ -1,40 +1,88 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) { - var topItem = nowPlayingItem, - bottomItem = null, - topText = nowPlayingItem.Name; - nowPlayingItem.AlbumId && "Audio" === nowPlayingItem.MediaType && (topItem = { - Id: nowPlayingItem.AlbumId, - Name: nowPlayingItem.Album, - Type: "MusicAlbum", - IsFolder: !0 - }), "Video" === nowPlayingItem.MediaType && (null != nowPlayingItem.IndexNumber && (topText = nowPlayingItem.IndexNumber + " - " + topText), null != nowPlayingItem.ParentIndexNumber && (topText = nowPlayingItem.ParentIndexNumber + "." + topText)); - var bottomText = ""; - nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length ? (bottomItem = { - Id: nowPlayingItem.ArtistItems[0].Id, - Name: nowPlayingItem.ArtistItems[0].Name, - Type: "MusicArtist", - IsFolder: !0 - }, bottomText = nowPlayingItem.ArtistItems.map(function(a) { - return a.Name - }).join(", ")) : nowPlayingItem.Artists && nowPlayingItem.Artists.length ? bottomText = nowPlayingItem.Artists.join(", ") : nowPlayingItem.SeriesName || nowPlayingItem.Album ? (bottomText = topText, topText = nowPlayingItem.SeriesName || nowPlayingItem.Album, bottomItem = topItem, topItem = nowPlayingItem.SeriesId ? { - Id: nowPlayingItem.SeriesId, - Name: nowPlayingItem.SeriesName, - Type: "Series", - IsFolder: !0 - } : null) : nowPlayingItem.ProductionYear && !1 !== includeNonNameInfo && (bottomText = nowPlayingItem.ProductionYear); + + var topItem = nowPlayingItem; + var bottomItem = null; + var topText = nowPlayingItem.Name; + + if (nowPlayingItem.AlbumId && nowPlayingItem.MediaType === 'Audio') { + topItem = { + Id: nowPlayingItem.AlbumId, + Name: nowPlayingItem.Album, + Type: 'MusicAlbum', + IsFolder: true + }; + } + + if (nowPlayingItem.MediaType === 'Video') { + if (nowPlayingItem.IndexNumber != null) { + topText = nowPlayingItem.IndexNumber + " - " + topText; + } + if (nowPlayingItem.ParentIndexNumber != null) { + topText = nowPlayingItem.ParentIndexNumber + "." + topText; + } + } + + var bottomText = ''; + + if (nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length) { + + bottomItem = { + Id: nowPlayingItem.ArtistItems[0].Id, + Name: nowPlayingItem.ArtistItems[0].Name, + Type: 'MusicArtist', + IsFolder: true + }; + + bottomText = nowPlayingItem.ArtistItems.map(function (a) { + return a.Name; + }).join(', '); + + } else if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) { + + bottomText = nowPlayingItem.Artists.join(', '); + } + else if (nowPlayingItem.SeriesName || nowPlayingItem.Album) { + bottomText = topText; + topText = nowPlayingItem.SeriesName || nowPlayingItem.Album; + + bottomItem = topItem; + + if (nowPlayingItem.SeriesId) { + topItem = { + Id: nowPlayingItem.SeriesId, + Name: nowPlayingItem.SeriesName, + Type: 'Series', + IsFolder: true + }; + } else { + topItem = null; + } + } + else if (nowPlayingItem.ProductionYear && includeNonNameInfo !== false) { + bottomText = nowPlayingItem.ProductionYear; + } + var list = []; - return list.push({ + + list.push({ text: topText, item: topItem - }), bottomText && list.push({ - text: bottomText, - item: bottomItem - }), list + }); + + if (bottomText) { + list.push({ + text: bottomText, + item: bottomItem + }); + } + + return list; } + return { getNowPlayingNames: getNowPlayingNames - } -}); \ No newline at end of file + }; +}); diff --git a/src/bower_components/emby-webcomponents/playback/playaccessvalidation.js b/src/bower_components/emby-webcomponents/playback/playaccessvalidation.js index 30a687d771..231ef09d0a 100644 --- a/src/bower_components/emby-webcomponents/playback/playaccessvalidation.js +++ b/src/bower_components/emby-webcomponents/playback/playaccessvalidation.js @@ -1,29 +1,56 @@ -define(["connectionManager", "globalize"], function(connectionManager, globalize) { +define(['connectionManager', 'globalize'], function (connectionManager, globalize) { "use strict"; function getRequirePromise(deps) { - return new Promise(function(resolve, reject) { - require(deps, resolve) - }) + + return new Promise(function (resolve, reject) { + + require(deps, resolve); + }); } function showErrorMessage() { - return getRequirePromise(["alert"]).then(function(alert) { - return alert(globalize.translate("sharedcomponents#MessagePlayAccessRestricted")).then(function() { - return Promise.reject() - }) - }) + return getRequirePromise(['alert']).then(function (alert) { + + return alert(globalize.translate('sharedcomponents#MessagePlayAccessRestricted')).then(function () { + return Promise.reject(); + }); + }); } function PlayAccessValidation() { - this.name = "Playback validation", this.type = "preplayintercept", this.id = "playaccessvalidation", this.order = -2 + + this.name = 'Playback validation'; + this.type = 'preplayintercept'; + this.id = 'playaccessvalidation'; + this.order = -2; } - return PlayAccessValidation.prototype.intercept = function(options) { + + PlayAccessValidation.prototype.intercept = function (options) { + var item = options.item; - if (!item) return Promise.resolve(); + if (!item) { + return Promise.resolve(); + } var serverId = item.ServerId; - return serverId ? connectionManager.getApiClient(serverId).getCurrentUser().then(function(user) { - return user.Policy.EnableMediaPlayback ? Promise.resolve() : options.fullscreen ? showErrorMessage() : Promise.reject() - }) : Promise.resolve() - }, PlayAccessValidation + if (!serverId) { + return Promise.resolve(); + } + + return connectionManager.getApiClient(serverId).getCurrentUser().then(function (user) { + + if (user.Policy.EnableMediaPlayback) { + return Promise.resolve(); + } + + // reject but don't show an error message + if (!options.fullscreen) { + return Promise.reject(); + } + + return showErrorMessage(); + }); + }; + + return PlayAccessValidation; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/playbackmanager.js b/src/bower_components/emby-webcomponents/playback/playbackmanager.js index a321efc36b..db70313ca0 100644 --- a/src/bower_components/emby-webcomponents/playback/playbackmanager.js +++ b/src/bower_components/emby-webcomponents/playback/playbackmanager.js @@ -1,153 +1,325 @@ -define(["events", "datetime", "appSettings", "itemHelper", "pluginManager", "playQueueManager", "userSettings", "globalize", "connectionManager", "loading", "apphost", "fullscreenManager"], function(events, datetime, appSettings, itemHelper, pluginManager, PlayQueueManager, userSettings, globalize, connectionManager, loading, apphost, fullscreenManager) { - "use strict"; +define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'playQueueManager', 'userSettings', 'globalize', 'connectionManager', 'loading', 'apphost', 'fullscreenManager'], function (events, datetime, appSettings, itemHelper, pluginManager, PlayQueueManager, userSettings, globalize, connectionManager, loading, apphost, fullscreenManager) { + 'use strict'; function enableLocalPlaylistManagement(player) { - return !player.getPlaylist && !!player.isLocalPlayer + + if (player.getPlaylist) { + + return false; + } + + if (player.isLocalPlayer) { + + return true; + } + + return false; } function bindToFullscreenChange(player) { - events.on(fullscreenManager, "fullscreenchange", function() { - events.trigger(player, "fullscreenchange") - }) + events.on(fullscreenManager, 'fullscreenchange', function () { + events.trigger(player, 'fullscreenchange'); + }); } function triggerPlayerChange(playbackManagerInstance, newPlayer, newTarget, previousPlayer, previousTargetInfo) { - (newPlayer || previousPlayer) && (newTarget && previousTargetInfo && newTarget.id === previousTargetInfo.id || events.trigger(playbackManagerInstance, "playerchange", [newPlayer, newTarget, previousPlayer])) + + if (!newPlayer && !previousPlayer) { + return; + } + + if (newTarget && previousTargetInfo) { + + if (newTarget.id === previousTargetInfo.id) { + return; + } + } + + events.trigger(playbackManagerInstance, 'playerchange', [newPlayer, newTarget, previousPlayer]); } function reportPlayback(playbackManagerInstance, state, player, reportPlaylist, serverId, method, progressEventName) { - if (serverId) { - var info = Object.assign({}, state.PlayState); - info.ItemId = state.NowPlayingItem.Id, progressEventName && (info.EventName = progressEventName), reportPlaylist && addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId); - connectionManager.getApiClient(serverId)[method](info) + + if (!serverId) { + // Not a server item + // We can expand on this later and possibly report them + return; } + + var info = Object.assign({}, state.PlayState); + info.ItemId = state.NowPlayingItem.Id; + + if (progressEventName) { + info.EventName = progressEventName; + } + + if (reportPlaylist) { + addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId); + } + + //console.log(method + '-' + JSON.stringify(info)); + var apiClient = connectionManager.getApiClient(serverId); + apiClient[method](info); } function getPlaylistSync(playbackManagerInstance, player) { - return player = player || playbackManagerInstance._currentPlayer, player && !enableLocalPlaylistManagement(player) ? player.getPlaylistSync() : playbackManagerInstance._playQueueManager.getPlaylist() + player = player || playbackManagerInstance._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.getPlaylistSync(); + } + + return playbackManagerInstance._playQueueManager.getPlaylist(); } function addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId) { - info.NowPlayingQueue = getPlaylistSync(playbackManagerInstance, player).map(function(i) { + + info.NowPlayingQueue = getPlaylistSync(playbackManagerInstance, player).map(function (i) { + var itemInfo = { Id: i.Id, PlaylistItemId: i.PlaylistItemId }; - return i.ServerId !== serverId && (itemInfo.ServerId = i.ServerId), itemInfo - }) + + if (i.ServerId !== serverId) { + itemInfo.ServerId = i.ServerId; + } + + return itemInfo; + }); } function normalizeName(t) { - return t.toLowerCase().replace(" ", "") + return t.toLowerCase().replace(' ', ''); } function getItemsForPlayback(serverId, query) { + var apiClient = connectionManager.getApiClient(serverId); - if (query.Ids && 1 === query.Ids.split(",").length) { - var itemId = query.Ids.split(","); - return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(item) { + + if (query.Ids && query.Ids.split(',').length === 1) { + + var itemId = query.Ids.split(','); + + return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { + return { Items: [item], TotalRecordCount: 1 - } - }) + }; + }); + } + else { + + query.Limit = query.Limit || 300; + query.Fields = "Chapters"; + query.ExcludeLocationTypes = "Virtual"; + query.EnableTotalRecordCount = false; + query.CollapseBoxSetItems = false; + + return apiClient.getItems(apiClient.getCurrentUserId(), query); } - return query.Limit = query.Limit || 300, query.Fields = "Chapters", query.ExcludeLocationTypes = "Virtual", query.EnableTotalRecordCount = !1, query.CollapseBoxSetItems = !1, apiClient.getItems(apiClient.getCurrentUserId(), query) } function createStreamInfoFromUrlItem(item) { + + // Check item.Path for games return { url: item.Url || item.Path, - playMethod: "DirectPlay", + playMethod: 'DirectPlay', item: item, textTracks: [], mediaType: item.MediaType - } + }; } function mergePlaybackQueries(obj1, obj2) { - var query = Object.assign(obj1, obj2), - filters = query.Filters ? query.Filters.split(",") : []; - return -1 === filters.indexOf("IsNotFolder") && filters.push("IsNotFolder"), query.Filters = filters.join(","), query + + var query = Object.assign(obj1, obj2); + + var filters = query.Filters ? query.Filters.split(',') : []; + if (filters.indexOf('IsNotFolder') === -1) { + filters.push('IsNotFolder'); + } + query.Filters = filters.join(','); + return query; } function backdropImageUrl(apiClient, item, options) { - return options = options || {}, options.type = options.type || "Backdrop", options.maxWidth || options.width || options.maxHeight || options.height || (options.quality = 100), item.BackdropImageTags && item.BackdropImageTags.length ? (options.tag = item.BackdropImageTags[0], apiClient.getScaledImageUrl(item.Id, options)) : item.ParentBackdropImageTags && item.ParentBackdropImageTags.length ? (options.tag = item.ParentBackdropImageTags[0], apiClient.getScaledImageUrl(item.ParentBackdropItemId, options)) : null + + options = options || {}; + options.type = options.type || "Backdrop"; + + // If not resizing, get the original image + if (!options.maxWidth && !options.width && !options.maxHeight && !options.height) { + options.quality = 100; + } + + if (item.BackdropImageTags && item.BackdropImageTags.length) { + + options.tag = item.BackdropImageTags[0]; + return apiClient.getScaledImageUrl(item.Id, options); + } + + if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { + options.tag = item.ParentBackdropImageTags[0]; + return apiClient.getScaledImageUrl(item.ParentBackdropItemId, options); + } + + return null; } function getMimeType(type, container) { - if (container = (container || "").toLowerCase(), "audio" === type) { - if ("opus" === container) return "audio/ogg"; - if ("webma" === container) return "audio/webm"; - if ("m4a" === container) return "audio/mp4" - } else if ("video" === type) { - if ("mkv" === container) return "video/x-matroska"; - if ("m4v" === container) return "video/mp4"; - if ("mov" === container) return "video/quicktime"; - if ("mpg" === container) return "video/mpeg"; - if ("flv" === container) return "video/x-flv" + + container = (container || '').toLowerCase(); + + if (type === 'audio') { + if (container === 'opus') { + return 'audio/ogg'; + } + if (container === 'webma') { + return 'audio/webm'; + } + if (container === 'm4a') { + return 'audio/mp4'; + } } - return type + "/" + container + else if (type === 'video') { + if (container === 'mkv') { + return 'video/x-matroska'; + } + if (container === 'm4v') { + return 'video/mp4'; + } + if (container === 'mov') { + return 'video/quicktime'; + } + if (container === 'mpg') { + return 'video/mpeg'; + } + if (container === 'flv') { + return 'video/x-flv'; + } + } + + return type + '/' + container; } function getParam(name, url) { - name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); - var regexS = "[\\?&]" + name + "=([^&#]*)", - regex = new RegExp(regexS, "i"), - results = regex.exec(url); - return null == results ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")) + name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); + var regexS = "[\\?&]" + name + "=([^&#]*)"; + var regex = new RegExp(regexS, "i"); + + var results = regex.exec(url); + if (results == null) { + return ""; + } + else { + return decodeURIComponent(results[1].replace(/\+/g, " ")); + } } function isAutomaticPlayer(player) { - return !!player.isLocalPlayer + + if (player.isLocalPlayer) { + return true; + } + + return false; } function getAutomaticPlayers(instance, forceLocalPlayer) { + if (!forceLocalPlayer) { var player = instance._currentPlayer; - if (player && !isAutomaticPlayer(player)) return [player] + if (player && !isAutomaticPlayer(player)) { + return [player]; + } } - return instance.getPlayers().filter(isAutomaticPlayer) + + return instance.getPlayers().filter(isAutomaticPlayer); } function isServerItem(item) { - return !!item.Id + if (!item.Id) { + return false; + } + return true; } function enableIntros(item) { - return "Video" === item.MediaType && ("TvChannel" !== item.Type && ("InProgress" !== item.Status && isServerItem(item))) + + if (item.MediaType !== 'Video') { + return false; + } + if (item.Type === 'TvChannel') { + return false; + } + // disable for in-progress recordings + if (item.Status === 'InProgress') { + return false; + } + + return isServerItem(item); } function getIntros(firstItem, apiClient, options) { - return options.startPositionTicks || options.startIndex || !1 === options.fullscreen || !enableIntros(firstItem) || !userSettings.enableCinemaMode() ? Promise.resolve({ - Items: [] - }) : apiClient.getIntros(firstItem.Id).then(function(result) { - return result - }, function(err) { + + if (options.startPositionTicks || options.startIndex || options.fullscreen === false || !enableIntros(firstItem) || !userSettings.enableCinemaMode()) { return Promise.resolve({ Items: [] - }) - }) + }); + } + + return apiClient.getIntros(firstItem.Id).then(function (result) { + + return result; + + }, function (err) { + + return Promise.resolve({ + Items: [] + }); + }); } function getAudioMaxValues(deviceProfile) { - var maxAudioSampleRate = null, - maxAudioBitDepth = null, - maxAudioBitrate = null; - return deviceProfile.CodecProfiles.map(function(codecProfile) { - "Audio" === codecProfile.Type && (codecProfile.Conditions || []).map(function(condition) { - "LessThanEqual" === condition.Condition && "AudioBitDepth" === condition.Property && (maxAudioBitDepth = condition.Value), "LessThanEqual" === condition.Condition && "AudioSampleRate" === condition.Property && (maxAudioSampleRate = condition.Value), "LessThanEqual" === condition.Condition && "AudioBitrate" === condition.Property && (maxAudioBitrate = condition.Value) - }) - }), { + + // TODO - this could vary per codec and should be done on the server using the entire profile + var maxAudioSampleRate = null; + var maxAudioBitDepth = null; + var maxAudioBitrate = null; + + deviceProfile.CodecProfiles.map(function (codecProfile) { + + if (codecProfile.Type === 'Audio') { + (codecProfile.Conditions || []).map(function (condition) { + if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioBitDepth') { + maxAudioBitDepth = condition.Value; + } + if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioSampleRate') { + maxAudioSampleRate = condition.Value; + } + if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioBitrate') { + maxAudioBitrate = condition.Value; + } + }); + } + }); + + return { maxAudioSampleRate: maxAudioSampleRate, maxAudioBitDepth: maxAudioBitDepth, maxAudioBitrate: maxAudioBitrate - } + }; } + var startingPlaySession = new Date().getTime(); function getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxAudioSampleRate, maxAudioBitDepth, maxAudioBitrate, startPosition) { - var url = "Audio/" + item.Id + "/universal"; - return startingPlaySession++, apiClient.getUrl(url, { + + var url = 'Audio/' + item.Id + '/universal'; + + startingPlaySession++; + return apiClient.getUrl(url, { UserId: apiClient.getCurrentUserId(), DeviceId: apiClient.deviceId(), MaxStreamingBitrate: maxAudioBitrate || maxBitrate, @@ -160,177 +332,415 @@ define(["events", "datetime", "appSettings", "itemHelper", "pluginManager", "pla api_key: apiClient.accessToken(), PlaySessionId: startingPlaySession, StartTimeTicks: startPosition || 0, - EnableRedirection: !0, - EnableRemoteMedia: apphost.supports("remoteaudio") - }) + EnableRedirection: true, + EnableRemoteMedia: apphost.supports('remoteaudio') + }); } function getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, apiClient, startPosition) { - var transcodingProfile = deviceProfile.TranscodingProfiles.filter(function(p) { - return "Audio" === p.Type && "Streaming" === p.Context - })[0], - directPlayContainers = ""; - deviceProfile.DirectPlayProfiles.map(function(p) { - "Audio" === p.Type && (directPlayContainers ? directPlayContainers += "," + p.Container : directPlayContainers = p.Container, p.AudioCodec && (directPlayContainers += "|" + p.AudioCodec)) + + var transcodingProfile = deviceProfile.TranscodingProfiles.filter(function (p) { + return p.Type === 'Audio' && p.Context === 'Streaming'; + })[0]; + + var directPlayContainers = ''; + + deviceProfile.DirectPlayProfiles.map(function (p) { + + if (p.Type === 'Audio') { + if (directPlayContainers) { + directPlayContainers += ',' + p.Container; + } else { + directPlayContainers = p.Container; + } + + if (p.AudioCodec) { + directPlayContainers += '|' + p.AudioCodec; + } + } + }); + var maxValues = getAudioMaxValues(deviceProfile); - return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition) + + return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition); } function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition) { - var audioTranscodingProfile = deviceProfile.TranscodingProfiles.filter(function(p) { - return "Audio" === p.Type && "Streaming" === p.Context - })[0], - audioDirectPlayContainers = ""; - deviceProfile.DirectPlayProfiles.map(function(p) { - "Audio" === p.Type && (audioDirectPlayContainers ? audioDirectPlayContainers += "," + p.Container : audioDirectPlayContainers = p.Container, p.AudioCodec && (audioDirectPlayContainers += "|" + p.AudioCodec)) + + var audioTranscodingProfile = deviceProfile.TranscodingProfiles.filter(function (p) { + return p.Type === 'Audio' && p.Context === 'Streaming'; + })[0]; + + var audioDirectPlayContainers = ''; + + deviceProfile.DirectPlayProfiles.map(function (p) { + + if (p.Type === 'Audio') { + if (audioDirectPlayContainers) { + audioDirectPlayContainers += ',' + p.Container; + } else { + audioDirectPlayContainers = p.Container; + } + + if (p.AudioCodec) { + audioDirectPlayContainers += '|' + p.AudioCodec; + } + } }); - for (var maxValues = getAudioMaxValues(deviceProfile), streamUrls = [], i = 0, length = items.length; i < length; i++) { - var streamUrl, item = items[i]; - "Audio" !== item.MediaType || itemHelper.isLocalItem(item) || (streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition)), streamUrls.push(streamUrl || ""), 0 === i && (startPosition = 0) + + var maxValues = getAudioMaxValues(deviceProfile); + + var streamUrls = []; + + for (var i = 0, length = items.length; i < length; i++) { + + var item = items[i]; + var streamUrl; + + if (item.MediaType === 'Audio' && !itemHelper.isLocalItem(item)) { + streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition); + } + + streamUrls.push(streamUrl || ''); + + if (i === 0) { + startPosition = 0; + } } - return Promise.resolve(streamUrls) + + return Promise.resolve(streamUrls); } function setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition) { - return getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition).then(function(streamUrls) { + + return getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition).then(function (streamUrls) { + for (var i = 0, length = items.length; i < length; i++) { - var item = items[i], - streamUrl = streamUrls[i]; - streamUrl && (item.PresetMediaSource = { - StreamUrl: streamUrl, - Id: item.Id, - MediaStreams: [], - RunTimeTicks: item.RunTimeTicks - }) + + var item = items[i]; + var streamUrl = streamUrls[i]; + + if (streamUrl) { + item.PresetMediaSource = { + StreamUrl: streamUrl, + Id: item.Id, + MediaStreams: [], + RunTimeTicks: item.RunTimeTicks + }; + } } - }) + }); } - function getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, isPlayback, mediaSourceId, audioStreamIndex, subtitleStreamIndex, liveStreamId, enableDirectPlay, enableDirectStream, allowVideoStreamCopy, allowAudioStreamCopy) { - if (!itemHelper.isLocalItem(item) && "Audio" === item.MediaType) return Promise.resolve({ - MediaSources: [{ - StreamUrl: getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, apiClient, startPosition), - Id: item.Id, - MediaStreams: [], - RunTimeTicks: item.RunTimeTicks - }] - }); - if (item.PresetMediaSource) return Promise.resolve({ - MediaSources: [item.PresetMediaSource] - }); - var itemId = item.Id, - query = { - UserId: apiClient.getCurrentUserId(), - StartTimeTicks: startPosition || 0 - }; - return isPlayback ? (query.IsPlayback = !0, query.AutoOpenLiveStream = !0) : (query.IsPlayback = !1, query.AutoOpenLiveStream = !1), null != audioStreamIndex && (query.AudioStreamIndex = audioStreamIndex), null != subtitleStreamIndex && (query.SubtitleStreamIndex = subtitleStreamIndex), null != enableDirectPlay && (query.EnableDirectPlay = enableDirectPlay), null != enableDirectStream && (query.EnableDirectStream = enableDirectStream), null != allowVideoStreamCopy && (query.AllowVideoStreamCopy = allowVideoStreamCopy), null != allowAudioStreamCopy && (query.AllowAudioStreamCopy = allowAudioStreamCopy), mediaSourceId && (query.MediaSourceId = mediaSourceId), liveStreamId && (query.LiveStreamId = liveStreamId), maxBitrate && (query.MaxStreamingBitrate = maxBitrate), player.enableMediaProbe && !player.enableMediaProbe(item) && (query.EnableMediaProbe = !1), !1 !== query.EnableDirectStream && player.supportsPlayMethod && !player.supportsPlayMethod("DirectStream", item) && (query.EnableDirectStream = !1), player.getDirectPlayProtocols && (query.DirectPlayProtocols = player.getDirectPlayProtocols()), apiClient.getPlaybackInfo(itemId, query, deviceProfile) + function getPlaybackInfo(player, + apiClient, + item, + deviceProfile, + maxBitrate, + startPosition, + isPlayback, + mediaSourceId, + audioStreamIndex, + subtitleStreamIndex, + liveStreamId, + enableDirectPlay, + enableDirectStream, + allowVideoStreamCopy, + allowAudioStreamCopy) { + + if (!itemHelper.isLocalItem(item) && item.MediaType === 'Audio') { + + return Promise.resolve({ + MediaSources: [ + { + StreamUrl: getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, apiClient, startPosition), + Id: item.Id, + MediaStreams: [], + RunTimeTicks: item.RunTimeTicks + }] + }); + } + + if (item.PresetMediaSource) { + return Promise.resolve({ + MediaSources: [item.PresetMediaSource] + }); + } + + var itemId = item.Id; + + var query = { + UserId: apiClient.getCurrentUserId(), + StartTimeTicks: startPosition || 0 + }; + + if (isPlayback) { + query.IsPlayback = true; + query.AutoOpenLiveStream = true; + } else { + query.IsPlayback = false; + query.AutoOpenLiveStream = false; + } + + if (audioStreamIndex != null) { + query.AudioStreamIndex = audioStreamIndex; + } + if (subtitleStreamIndex != null) { + query.SubtitleStreamIndex = subtitleStreamIndex; + } + if (enableDirectPlay != null) { + query.EnableDirectPlay = enableDirectPlay; + } + + if (enableDirectStream != null) { + query.EnableDirectStream = enableDirectStream; + } + if (allowVideoStreamCopy != null) { + query.AllowVideoStreamCopy = allowVideoStreamCopy; + } + if (allowAudioStreamCopy != null) { + query.AllowAudioStreamCopy = allowAudioStreamCopy; + } + if (mediaSourceId) { + query.MediaSourceId = mediaSourceId; + } + if (liveStreamId) { + query.LiveStreamId = liveStreamId; + } + if (maxBitrate) { + query.MaxStreamingBitrate = maxBitrate; + } + if (player.enableMediaProbe && !player.enableMediaProbe(item)) { + query.EnableMediaProbe = false; + } + + // lastly, enforce player overrides for special situations + if (query.EnableDirectStream !== false) { + if (player.supportsPlayMethod && !player.supportsPlayMethod('DirectStream', item)) { + query.EnableDirectStream = false; + } + } + + if (player.getDirectPlayProtocols) { + query.DirectPlayProtocols = player.getDirectPlayProtocols(); + } + + return apiClient.getPlaybackInfo(itemId, query, deviceProfile); } function getOptimalMediaSource(apiClient, item, versions) { - var promises = versions.map(function(v) { - return supportsDirectPlay(apiClient, item, v) + + var promises = versions.map(function (v) { + return supportsDirectPlay(apiClient, item, v); }); - return promises.length ? Promise.all(promises).then(function(results) { - for (var i = 0, length = versions.length; i < length; i++) versions[i].enableDirectPlay = results[i] || !1; - var optimalVersion = versions.filter(function(v) { - return v.enableDirectPlay + + if (!promises.length) { + return Promise.reject(); + } + + return Promise.all(promises).then(function (results) { + + for (var i = 0, length = versions.length; i < length; i++) { + versions[i].enableDirectPlay = results[i] || false; + } + var optimalVersion = versions.filter(function (v) { + + return v.enableDirectPlay; + })[0]; - return optimalVersion || (optimalVersion = versions.filter(function(v) { - return v.SupportsDirectStream - })[0]), (optimalVersion = optimalVersion || versions.filter(function(s) { - return s.SupportsTranscoding - })[0]) || versions[0] - }) : Promise.reject() + + if (!optimalVersion) { + optimalVersion = versions.filter(function (v) { + + return v.SupportsDirectStream; + + })[0]; + } + + optimalVersion = optimalVersion || versions.filter(function (s) { + return s.SupportsTranscoding; + })[0]; + + return optimalVersion || versions[0]; + }); } function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, maxBitrate, startPosition, mediaSource, audioStreamIndex, subtitleStreamIndex) { + var postData = { - DeviceProfile: deviceProfile, - OpenToken: mediaSource.OpenToken - }, - query = { - UserId: apiClient.getCurrentUserId(), - StartTimeTicks: startPosition || 0, - ItemId: item.Id, - PlaySessionId: playSessionId - }; - return maxBitrate && (query.MaxStreamingBitrate = maxBitrate), null != audioStreamIndex && (query.AudioStreamIndex = audioStreamIndex), null != subtitleStreamIndex && (query.SubtitleStreamIndex = subtitleStreamIndex), !1 !== query.EnableDirectStream && player.supportsPlayMethod && !player.supportsPlayMethod("DirectStream", item) && (query.EnableDirectStream = !1), apiClient.ajax({ - url: apiClient.getUrl("LiveStreams/Open", query), - type: "POST", + DeviceProfile: deviceProfile, + OpenToken: mediaSource.OpenToken + }; + + var query = { + UserId: apiClient.getCurrentUserId(), + StartTimeTicks: startPosition || 0, + ItemId: item.Id, + PlaySessionId: playSessionId + }; + + if (maxBitrate) { + query.MaxStreamingBitrate = maxBitrate; + } + if (audioStreamIndex != null) { + query.AudioStreamIndex = audioStreamIndex; + } + if (subtitleStreamIndex != null) { + query.SubtitleStreamIndex = subtitleStreamIndex; + } + + // lastly, enforce player overrides for special situations + if (query.EnableDirectStream !== false) { + if (player.supportsPlayMethod && !player.supportsPlayMethod('DirectStream', item)) { + query.EnableDirectStream = false; + } + } + + return apiClient.ajax({ + url: apiClient.getUrl('LiveStreams/Open', query), + type: 'POST', data: JSON.stringify(postData), contentType: "application/json", dataType: "json" - }) + + }); } function isHostReachable(mediaSource, apiClient) { - return mediaSource.IsRemote ? Promise.resolve(!0) : apiClient.getEndpointInfo().then(function(endpointInfo) { + + if (mediaSource.IsRemote) { + return Promise.resolve(true); + } + + return apiClient.getEndpointInfo().then(function (endpointInfo) { + if (endpointInfo.IsInNetwork) { + if (!endpointInfo.IsLocal) { - var path = (mediaSource.Path || "").toLowerCase(); - if (-1 !== path.indexOf("localhost") || -1 !== path.indexOf("127.0.0.1")) return Promise.resolve(!1) + var path = (mediaSource.Path || '').toLowerCase(); + if (path.indexOf('localhost') !== -1 || path.indexOf('127.0.0.1') !== -1) { + // This will only work if the app is on the same machine as the server + return Promise.resolve(false); + } } - return Promise.resolve(!0) + + return Promise.resolve(true); } - return Promise.resolve(!1) - }) + + // media source is in network, but connection is out of network + return Promise.resolve(false); + }); } function supportsDirectPlay(apiClient, item, mediaSource) { - var isFolderRip = "BluRay" === mediaSource.VideoType || "Dvd" === mediaSource.VideoType || "HdDvd" === mediaSource.VideoType; + + // folder rip hacks due to not yet being supported by the stream building engine + var isFolderRip = mediaSource.VideoType === 'BluRay' || mediaSource.VideoType === 'Dvd' || mediaSource.VideoType === 'HdDvd'; + if (mediaSource.SupportsDirectPlay || isFolderRip) { - if (mediaSource.IsRemote && !apphost.supports("remotevideo")) return Promise.resolve(!1); - if ("Http" === mediaSource.Protocol && !mediaSource.RequiredHttpHeaders.length) return mediaSource.SupportsDirectStream || mediaSource.SupportsTranscoding ? isHostReachable(mediaSource, apiClient) : Promise.resolve(!0); - if ("File" === mediaSource.Protocol) return new Promise(function(resolve, reject) { - require(["filesystem"], function(filesystem) { - filesystem[isFolderRip ? "directoryExists" : "fileExists"](mediaSource.Path).then(function() { - resolve(!0) - }, function() { - resolve(!1) - }) - }) - }) + + if (mediaSource.IsRemote && !apphost.supports('remotevideo')) { + return Promise.resolve(false); + } + + if (mediaSource.Protocol === 'Http' && !mediaSource.RequiredHttpHeaders.length) { + + // If this is the only way it can be played, then allow it + if (!mediaSource.SupportsDirectStream && !mediaSource.SupportsTranscoding) { + return Promise.resolve(true); + } + else { + return isHostReachable(mediaSource, apiClient); + } + } + + else if (mediaSource.Protocol === 'File') { + + return new Promise(function (resolve, reject) { + + // Determine if the file can be accessed directly + require(['filesystem'], function (filesystem) { + + var method = isFolderRip ? + 'directoryExists' : + 'fileExists'; + + filesystem[method](mediaSource.Path).then(function () { + resolve(true); + }, function () { + resolve(false); + }); + + }); + }); + } } - return Promise.resolve(!1) + + return Promise.resolve(false); } function validatePlaybackInfoResult(instance, result) { - return !result.ErrorCode || (showPlaybackInfoErrorMessage(instance, result.ErrorCode), !1) + + if (result.ErrorCode) { + + showPlaybackInfoErrorMessage(instance, result.ErrorCode); + return false; + } + + return true; } function showPlaybackInfoErrorMessage(instance, errorCode, playNextTrack) { - require(["alert"], function(alert) { + + require(['alert'], function (alert) { alert({ - text: globalize.translate("sharedcomponents#PlaybackError" + errorCode), - title: globalize.translate("sharedcomponents#HeaderPlaybackError") - }).then(function() { - playNextTrack && instance.nextTrack() - }) - }) + text: globalize.translate('sharedcomponents#PlaybackError' + errorCode), + title: globalize.translate('sharedcomponents#HeaderPlaybackError') + }).then(function () { + + if (playNextTrack) { + instance.nextTrack(); + } + }); + }); } function normalizePlayOptions(playOptions) { - playOptions.fullscreen = !1 !== playOptions.fullscreen + playOptions.fullscreen = playOptions.fullscreen !== false; } function truncatePlayOptions(playOptions) { + return { fullscreen: playOptions.fullscreen, mediaSourceId: playOptions.mediaSourceId, audioStreamIndex: playOptions.audioStreamIndex, subtitleStreamIndex: playOptions.subtitleStreamIndex, startPositionTicks: playOptions.startPositionTicks - } + }; } function getNowPlayingItemForReporting(player, item, mediaSource) { + var nowPlayingItem = Object.assign({}, item); - return mediaSource && (nowPlayingItem.RunTimeTicks = mediaSource.RunTimeTicks, nowPlayingItem.MediaStreams = mediaSource.MediaStreams, nowPlayingItem.MediaSources = null), nowPlayingItem.RunTimeTicks = nowPlayingItem.RunTimeTicks || 1e4 * player.duration(), nowPlayingItem + + if (mediaSource) { + nowPlayingItem.RunTimeTicks = mediaSource.RunTimeTicks; + nowPlayingItem.MediaStreams = mediaSource.MediaStreams; + + // not needed + nowPlayingItem.MediaSources = null; + } + + nowPlayingItem.RunTimeTicks = nowPlayingItem.RunTimeTicks || player.duration() * 10000; + + return nowPlayingItem; } function displayPlayerIndividually(player) { - return !player.isLocalPlayer + + return !player.isLocalPlayer; } function createTarget(instance, player) { @@ -338,1215 +748,3241 @@ define(["events", "datetime", "appSettings", "itemHelper", "pluginManager", "pla name: player.name, id: player.id, playerName: player.name, - playableMediaTypes: ["Audio", "Video", "Game", "Photo", "Book"].map(player.canPlayMediaType), + playableMediaTypes: ['Audio', 'Video', 'Game', 'Photo', 'Book'].map(player.canPlayMediaType), isLocalPlayer: player.isLocalPlayer, supportedCommands: instance.getSupportedCommands(player) - } + }; } function getPlayerTargets(player) { - return player.getTargets ? player.getTargets() : Promise.resolve([createTarget(player)]) + if (player.getTargets) { + return player.getTargets(); + } + + return Promise.resolve([createTarget(player)]); } function sortPlayerTargets(a, b) { - var aVal = a.isLocalPlayer ? 0 : 1, - bVal = b.isLocalPlayer ? 0 : 1; - return aVal = aVal.toString() + a.name, bVal = bVal.toString() + b.name, aVal.localeCompare(bVal) + + var aVal = a.isLocalPlayer ? 0 : 1; + var bVal = b.isLocalPlayer ? 0 : 1; + + aVal = aVal.toString() + a.name; + bVal = bVal.toString() + b.name; + + return aVal.localeCompare(bVal); } function PlaybackManager() { - function getCurrentSubtitleStream(player) { - if (!player) throw new Error("player cannot be null"); - var index = getPlayerData(player).subtitleStreamIndex; - return null == index || -1 === index ? null : getSubtitleStream(player, index) - } - function getSubtitleStream(player, index) { - return self.subtitleTracks(player).filter(function(s) { - return "Subtitle" === s.Type && s.Index === index - })[0] - } + var self = this; - function removeCurrentPlayer(player) { - var previousPlayer = self._currentPlayer; - previousPlayer && player.id !== previousPlayer.id || setCurrentPlayerInternal(null) - } + var players = []; + var currentTargetInfo; + var lastLocalPlayer; + var currentPairingId = null; - function setCurrentPlayerInternal(player, targetInfo) { - var previousPlayer = self._currentPlayer, - previousTargetInfo = currentTargetInfo; - if (player && !targetInfo && player.isLocalPlayer && (targetInfo = createTarget(self, player)), player && !targetInfo) throw new Error("targetInfo cannot be null"); - currentPairingId = null, self._currentPlayer = player, currentTargetInfo = targetInfo, targetInfo && console.log("Active player: " + JSON.stringify(targetInfo)), player && player.isLocalPlayer && (lastLocalPlayer = player), previousPlayer && self.endPlayerUpdates(previousPlayer), player && self.beginPlayerUpdates(player), triggerPlayerChange(self, player, targetInfo, previousPlayer, previousTargetInfo) - } - - function getDefaultPlayOptions() { - return { - fullscreen: !0 - } - } - - function isAudioStreamSupported(mediaSource, index, deviceProfile) { - var mediaStream, i, length, mediaStreams = mediaSource.MediaStreams; - for (i = 0, length = mediaStreams.length; i < length; i++) - if ("Audio" === mediaStreams[i].Type && mediaStreams[i].Index === index) { - mediaStream = mediaStreams[i]; - break - } if (!mediaStream) return !1; - var codec = (mediaStream.Codec || "").toLowerCase(); - return !!codec && (deviceProfile.DirectPlayProfiles || []).filter(function(p) { - return "Video" === p.Type && (!p.AudioCodec || (0 === p.AudioCodec.indexOf("-") ? -1 === p.AudioCodec.toLowerCase().indexOf(codec) : -1 !== p.AudioCodec.toLowerCase().indexOf(codec))) - }).length > 0 - } - - function getSavedMaxStreamingBitrate(apiClient, mediaType) { - apiClient || (apiClient = connectionManager.currentApiClient()); - var endpointInfo = apiClient.getSavedEndpointInfo() || {}; - return appSettings.maxStreamingBitrate(endpointInfo.IsInNetwork, mediaType) - } - - function getDeliveryMethod(subtitleStream) { - return subtitleStream.DeliveryMethod ? subtitleStream.DeliveryMethod : subtitleStream.IsExternal ? "External" : "Embed" - } - - function canPlayerSeek(player) { - if (!player) throw new Error("player cannot be null"); - return -1 !== (getPlayerData(player).streamInfo.url || "").toLowerCase().indexOf(".m3u8") || (player.seekable ? player.seekable() : !("Transcode" === self.playMethod(player)) && player.duration()) - } - - function changeStream(player, ticks, params) { - if (canPlayerSeek(player) && null == params) return void player.currentTime(parseInt(ticks / 1e4)); - params = params || {}; - var liveStreamId = getPlayerData(player).streamInfo.liveStreamId, - lastMediaInfoQuery = getPlayerData(player).streamInfo.lastMediaInfoQuery, - playSessionId = self.playSessionId(player), - currentItem = self.currentItem(player); - player.getDeviceProfile(currentItem, { - isRetry: !1 === params.EnableDirectPlay - }).then(function(deviceProfile) { - var audioStreamIndex = null == params.AudioStreamIndex ? getPlayerData(player).audioStreamIndex : params.AudioStreamIndex, - subtitleStreamIndex = null == params.SubtitleStreamIndex ? getPlayerData(player).subtitleStreamIndex : params.SubtitleStreamIndex, - currentMediaSource = self.currentMediaSource(player), - apiClient = connectionManager.getApiClient(currentItem.ServerId); - ticks && (ticks = parseInt(ticks)); - var maxBitrate = params.MaxStreamingBitrate || self.getMaxStreamingBitrate(player), - currentPlayOptions = currentItem.playOptions || {}; - getPlaybackInfo(player, apiClient, currentItem, deviceProfile, maxBitrate, ticks, !0, currentMediaSource.Id, audioStreamIndex, subtitleStreamIndex, liveStreamId, params.EnableDirectPlay, params.EnableDirectStream, params.AllowVideoStreamCopy, params.AllowAudioStreamCopy).then(function(result) { - if (validatePlaybackInfoResult(self, result)) { - currentMediaSource = result.MediaSources[0]; - var streamInfo = createStreamInfo(apiClient, currentItem.MediaType, currentItem, currentMediaSource, ticks); - if (streamInfo.fullscreen = currentPlayOptions.fullscreen, streamInfo.lastMediaInfoQuery = lastMediaInfoQuery, !streamInfo.url) return void showPlaybackInfoErrorMessage(self, "NoCompatibleStream", !0); - getPlayerData(player).subtitleStreamIndex = subtitleStreamIndex, getPlayerData(player).audioStreamIndex = audioStreamIndex, getPlayerData(player).maxStreamingBitrate = maxBitrate, changeStreamToUrl(apiClient, player, playSessionId, streamInfo) - } - }) - }) - } - - function changeStreamToUrl(apiClient, player, playSessionId, streamInfo, newPositionTicks) { - var playerData = getPlayerData(player); - playerData.isChangingStream = !0, playerData.streamInfo && playSessionId ? apiClient.stopActiveEncodings(playSessionId).then(function() { - var afterSetSrc = function() { - apiClient.stopActiveEncodings(playSessionId) - }; - setSrcIntoPlayer(apiClient, player, streamInfo).then(afterSetSrc, afterSetSrc) - }) : setSrcIntoPlayer(apiClient, player, streamInfo) - } - - function setSrcIntoPlayer(apiClient, player, streamInfo) { - return player.play(streamInfo).then(function() { - var playerData = getPlayerData(player); - playerData.isChangingStream = !1, playerData.streamInfo = streamInfo, streamInfo.started = !0, streamInfo.ended = !1, sendProgressUpdate(player, "timeupdate") - }, function(e) { - getPlayerData(player).isChangingStream = !1, onPlaybackError.call(player, e, { - type: "mediadecodeerror", - streamInfo: streamInfo - }) - }) - } - - function translateItemsForPlayback(items, options) { - var promise, firstItem = items[0], - serverId = firstItem.ServerId, - queryOptions = options.queryOptions || {}; - return "Program" === firstItem.Type ? promise = getItemsForPlayback(serverId, { - Ids: firstItem.ChannelId - }) : "Playlist" === firstItem.Type ? promise = getItemsForPlayback(serverId, { - ParentId: firstItem.Id, - SortBy: options.shuffle ? "Random" : null - }) : "MusicArtist" === firstItem.Type ? promise = getItemsForPlayback(serverId, { - ArtistIds: firstItem.Id, - Filters: "IsNotFolder", - Recursive: !0, - SortBy: options.shuffle ? "Random" : "SortName", - MediaTypes: "Audio" - }) : "Photo" === firstItem.MediaType ? promise = getItemsForPlayback(serverId, { - ParentId: firstItem.ParentId, - Filters: "IsNotFolder", - Recursive: !1, - SortBy: options.shuffle ? "Random" : "SortName", - MediaTypes: "Photo,Video", - Limit: 5e3 - }).then(function(result) { - var items = result.Items, - index = items.map(function(i) { - return i.Id - }).indexOf(firstItem.Id); - return -1 === index && (index = 0), options.startIndex = index, Promise.resolve(result) - }) : "PhotoAlbum" === firstItem.Type ? promise = getItemsForPlayback(serverId, { - ParentId: firstItem.Id, - Filters: "IsNotFolder", - Recursive: !1, - SortBy: options.shuffle ? "Random" : "SortName", - MediaTypes: "Photo,Video", - Limit: 1e3 - }) : "MusicGenre" === firstItem.Type ? promise = getItemsForPlayback(serverId, { - GenreIds: firstItem.Id, - Filters: "IsNotFolder", - Recursive: !0, - SortBy: options.shuffle ? "Random" : "SortName", - MediaTypes: "Audio" - }) : firstItem.IsFolder ? promise = getItemsForPlayback(serverId, mergePlaybackQueries({ - ParentId: firstItem.Id, - Filters: "IsNotFolder", - Recursive: !0, - SortBy: options.shuffle ? "Random" : -1 === ["BoxSet"].indexOf(firstItem.Type) ? "SortName" : null, - MediaTypes: "Audio,Video" - }, queryOptions)) : "Episode" === firstItem.Type && 1 === items.length && !1 !== getPlayer(firstItem, options).supportsProgress && (promise = new Promise(function(resolve, reject) { - var apiClient = connectionManager.getApiClient(firstItem.ServerId); - apiClient.getCurrentUser().then(function(user) { - if (!user.Configuration.EnableNextEpisodeAutoPlay || !firstItem.SeriesId) return void resolve(null); - apiClient.getEpisodes(firstItem.SeriesId, { - IsVirtualUnaired: !1, - IsMissing: !1, - UserId: apiClient.getCurrentUserId(), - Fields: "Chapters" - }).then(function(episodesResult) { - var foundItem = !1; - episodesResult.Items = episodesResult.Items.filter(function(e) { - return !!foundItem || e.Id === firstItem.Id && (foundItem = !0, !0) - }), episodesResult.TotalRecordCount = episodesResult.Items.length, resolve(episodesResult) - }, reject) - }) - })), promise ? promise.then(function(result) { - return result ? result.Items : items - }) : Promise.resolve(items) - } - - function getPlayerData(player) { - if (!player) throw new Error("player cannot be null"); - if (!player.name) throw new Error("player name cannot be null"); - var state = playerStates[player.name]; - return state || (playerStates[player.name] = {}, state = playerStates[player.name]), player - } - - function getCurrentTicks(player) { - if (!player) throw new Error("player cannot be null"); - var playerTime = Math.floor(1e4 * (player || self._currentPlayer).currentTime()); - return getPlayerData(player).streamInfo && (playerTime += getPlayerData(player).streamInfo.transcodingOffsetTicks || 0), playerTime - } - - function playPhotos(items, options, user) { - var playStartIndex = options.startIndex || 0, - player = getPlayer(items[playStartIndex], options); - return loading.hide(), options.items = items, player.play(options) - } - - function playWithIntros(items, options, user) { - var playStartIndex = options.startIndex || 0, - firstItem = items[playStartIndex]; - if (firstItem || (playStartIndex = 0, firstItem = items[playStartIndex]), !firstItem) return showPlaybackInfoErrorMessage(self, "NoCompatibleStream", !1), Promise.reject(); - if ("Photo" === firstItem.MediaType) return playPhotos(items, options, user); - var apiClient = connectionManager.getApiClient(firstItem.ServerId); - return getIntros(firstItem, apiClient, options).then(function(introsResult) { - var introPlayOptions, introItems = introsResult.Items; - return firstItem.playOptions = truncatePlayOptions(options), introPlayOptions = introItems.length ? { - fullscreen: firstItem.playOptions.fullscreen - } : firstItem.playOptions, items = introItems.concat(items), introPlayOptions.items = items, introPlayOptions.startIndex = playStartIndex, playInternal(items[playStartIndex], introPlayOptions, function() { - self._playQueueManager.setPlaylist(items), setPlaylistState(items[playStartIndex].PlaylistItemId, playStartIndex), loading.hide() - }) - }) - } - - function setPlaylistState(playlistItemId, index) { - isNaN(index) || self._playQueueManager.setPlaylistState(playlistItemId, index) - } - - function playInternal(item, playOptions, onPlaybackStartedFn) { - return item.IsPlaceHolder ? (loading.hide(), showPlaybackInfoErrorMessage(self, "PlaceHolder", !0), Promise.reject()) : (normalizePlayOptions(playOptions), playOptions.isFirstItem ? playOptions.isFirstItem = !1 : playOptions.isFirstItem = !0, runInterceptors(item, playOptions).then(function() { - playOptions.fullscreen && loading.show(); - var mediaType = item.MediaType, - onBitrateDetectionFailure = function() { - return playAfterBitrateDetect(getSavedMaxStreamingBitrate(connectionManager.getApiClient(item.ServerId), mediaType), item, playOptions, onPlaybackStartedFn) - }; - if (!isServerItem(item) || itemHelper.isLocalItem(item)) return onBitrateDetectionFailure(); - var apiClient = connectionManager.getApiClient(item.ServerId); - apiClient.getEndpointInfo().then(function(endpointInfo) { - if (("Video" === mediaType || "Audio" === mediaType) && appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType)) return apiClient.detectBitrate().then(function(bitrate) { - return appSettings.maxStreamingBitrate(endpointInfo.IsInNetwork, mediaType, bitrate), playAfterBitrateDetect(bitrate, item, playOptions, onPlaybackStartedFn) - }, onBitrateDetectionFailure); - onBitrateDetectionFailure() - }, onBitrateDetectionFailure) - }, onInterceptorRejection)) - } - - function onInterceptorRejection() { - var player = self._currentPlayer; - return player && (destroyPlayer(player), removeCurrentPlayer(player)), events.trigger(self, "playbackcancelled"), Promise.reject() - } - - function destroyPlayer(player) { - player.destroy() - } - - function runInterceptors(item, playOptions) { - return new Promise(function(resolve, reject) { - var interceptors = pluginManager.ofType("preplayintercept"); - if (interceptors.sort(function(a, b) { - return (a.order || 0) - (b.order || 0) - }), !interceptors.length) return void resolve(); - loading.hide(); - var options = Object.assign({}, playOptions); - options.mediaType = item.MediaType, options.item = item, runNextPrePlay(interceptors, 0, options, resolve, reject) - }) - } - - function runNextPrePlay(interceptors, index, options, resolve, reject) { - if (index >= interceptors.length) return void resolve(); - interceptors[index].intercept(options).then(function() { - runNextPrePlay(interceptors, index + 1, options, resolve, reject) - }, reject) - } - - function sendPlaybackListToPlayer(player, items, deviceProfile, maxBitrate, apiClient, startPositionTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, startIndex) { - return setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositionTicks).then(function() { - return loading.hide(), player.play({ - items: items, - startPositionTicks: startPositionTicks || 0, - mediaSourceId: mediaSourceId, - audioStreamIndex: audioStreamIndex, - subtitleStreamIndex: subtitleStreamIndex, - startIndex: startIndex - }) - }) - } - - function playAfterBitrateDetect(maxBitrate, item, playOptions, onPlaybackStartedFn) { - var promise, startPosition = playOptions.startPositionTicks, - player = getPlayer(item, playOptions), - activePlayer = self._currentPlayer; - return activePlayer ? (self._playNextAfterEnded = !1, promise = onPlaybackChanging(activePlayer, player, item)) : promise = Promise.resolve(), isServerItem(item) && "Game" !== item.MediaType && "Book" !== item.MediaType ? Promise.all([promise, player.getDeviceProfile(item)]).then(function(responses) { - var deviceProfile = responses[1], - apiClient = connectionManager.getApiClient(item.ServerId), - mediaSourceId = playOptions.mediaSourceId, - audioStreamIndex = playOptions.audioStreamIndex, - subtitleStreamIndex = playOptions.subtitleStreamIndex; - return player && !enableLocalPlaylistManagement(player) ? sendPlaybackListToPlayer(player, playOptions.items, deviceProfile, maxBitrate, apiClient, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex, playOptions.startIndex) : (playOptions.items = null, getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex).then(function(mediaSource) { - var streamInfo = createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition); - return streamInfo.fullscreen = playOptions.fullscreen, getPlayerData(player).isChangingStream = !1, getPlayerData(player).maxStreamingBitrate = maxBitrate, player.play(streamInfo).then(function() { - loading.hide(), onPlaybackStartedFn(), onPlaybackStarted(player, playOptions, streamInfo, mediaSource) - }, function(err) { - onPlaybackStartedFn(), onPlaybackStarted(player, playOptions, streamInfo, mediaSource), setTimeout(function() { - onPlaybackError.call(player, err, { - type: "mediadecodeerror", - streamInfo: streamInfo - }) - }, 100) - }) - })) - }) : promise.then(function() { - var streamInfo = createStreamInfoFromUrlItem(item); - return streamInfo.fullscreen = playOptions.fullscreen, getPlayerData(player).isChangingStream = !1, player.play(streamInfo).then(function() { - loading.hide(), onPlaybackStartedFn(), onPlaybackStarted(player, playOptions, streamInfo) - }, function() { - self.stop(player) - }) - }) - } - - function createStreamInfo(apiClient, type, item, mediaSource, startPosition) { - var mediaUrl, contentType, directOptions, transcodingOffsetTicks = 0, - playerStartPositionTicks = startPosition, - liveStreamId = mediaSource.LiveStreamId, - playMethod = "Transcode", - mediaSourceContainer = (mediaSource.Container || "").toLowerCase(); - if ("Video" === type || "Audio" === type) - if (contentType = getMimeType(type.toLowerCase(), mediaSourceContainer), mediaSource.enableDirectPlay) mediaUrl = mediaSource.Path, playMethod = "DirectPlay"; - else if (mediaSource.StreamUrl) playMethod = "Transcode", mediaUrl = mediaSource.StreamUrl; - else if (mediaSource.SupportsDirectStream) { - directOptions = { - Static: !0, - mediaSourceId: mediaSource.Id, - deviceId: apiClient.deviceId(), - api_key: apiClient.accessToken() - }, mediaSource.ETag && (directOptions.Tag = mediaSource.ETag), mediaSource.LiveStreamId && (directOptions.LiveStreamId = mediaSource.LiveStreamId); - var prefix = "Video" === type ? "Videos" : "Audio"; - mediaUrl = apiClient.getUrl(prefix + "/" + item.Id + "/stream." + mediaSourceContainer, directOptions), playMethod = "DirectStream" - } else mediaSource.SupportsTranscoding && (mediaUrl = apiClient.getUrl(mediaSource.TranscodingUrl), "hls" === mediaSource.TranscodingSubProtocol ? contentType = "application/x-mpegURL" : (playerStartPositionTicks = null, contentType = getMimeType(type.toLowerCase(), mediaSource.TranscodingContainer), -1 === mediaUrl.toLowerCase().indexOf("copytimestamps=true") && (transcodingOffsetTicks = startPosition || 0))); - else mediaUrl = mediaSource.Path, playMethod = "DirectPlay"; - !mediaUrl && mediaSource.SupportsDirectPlay && (mediaUrl = mediaSource.Path, playMethod = "DirectPlay"); - var resultInfo = { - url: mediaUrl, - mimeType: contentType, - transcodingOffsetTicks: transcodingOffsetTicks, - playMethod: playMethod, - playerStartPositionTicks: playerStartPositionTicks, - item: item, - mediaSource: mediaSource, - textTracks: getTextTracks(apiClient, item, mediaSource), - tracks: getTextTracks(apiClient, item, mediaSource), - mediaType: type, - liveStreamId: liveStreamId, - playSessionId: getParam("playSessionId", mediaUrl), - title: item.Name - }, - backdropUrl = backdropImageUrl(apiClient, item, {}); - return backdropUrl && (resultInfo.backdropUrl = backdropUrl), resultInfo - } - - function getTextTracks(apiClient, item, mediaSource) { - for (var subtitleStreams = mediaSource.MediaStreams.filter(function(s) { - return "Subtitle" === s.Type - }), textStreams = subtitleStreams.filter(function(s) { - return "External" === s.DeliveryMethod - }), tracks = [], i = 0, length = textStreams.length; i < length; i++) { - var textStreamUrl, textStream = textStreams[i]; - textStreamUrl = itemHelper.isLocalItem(item) ? textStream.Path : textStream.IsExternalUrl ? textStream.DeliveryUrl : apiClient.getUrl(textStream.DeliveryUrl), tracks.push({ - url: textStreamUrl, - language: textStream.Language || "und", - isDefault: textStream.Index === mediaSource.DefaultSubtitleStreamIndex, - index: textStream.Index, - format: textStream.Codec - }) - } - return tracks - } - - function getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex) { - return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, !0, mediaSourceId, audioStreamIndex, subtitleStreamIndex, null).then(function(playbackInfoResult) { - return validatePlaybackInfoResult(self, playbackInfoResult) ? getOptimalMediaSource(apiClient, item, playbackInfoResult.MediaSources).then(function(mediaSource) { - return mediaSource ? mediaSource.RequiresOpening && !mediaSource.LiveStreamId ? getLiveStream(player, apiClient, item, playbackInfoResult.PlaySessionId, deviceProfile, maxBitrate, startPosition, mediaSource, null, null).then(function(openLiveStreamResult) { - return supportsDirectPlay(apiClient, item, openLiveStreamResult.MediaSource).then(function(result) { - return openLiveStreamResult.MediaSource.enableDirectPlay = result, openLiveStreamResult.MediaSource - }) - }) : mediaSource : (showPlaybackInfoErrorMessage(self, "NoCompatibleStream"), Promise.reject()) - }) : Promise.reject() - }) - } - - function getPlayer(item, playOptions, forceLocalPlayers) { - var serverItem = isServerItem(item); - return getAutomaticPlayers(self, forceLocalPlayers).filter(function(p) { - if (p.canPlayMediaType(item.MediaType)) { - if (serverItem) return !p.canPlayItem || p.canPlayItem(item, playOptions); - if (item.Url && p.canPlayUrl) return p.canPlayUrl(item.Url) - } - return !1 - })[0] - } - - function queue(options, mode, player) { - if (!(player = player || self._currentPlayer)) return self.play(options); - if (options.items) return translateItemsForPlayback(options.items, options).then(function(items) { - queueAll(items, mode, player) - }); - if (!options.serverId) throw new Error("serverId required!"); - return getItemsForPlayback(options.serverId, { - Ids: options.ids.join(",") - }).then(function(result) { - return translateItemsForPlayback(result.Items, options).then(function(items) { - queueAll(items, mode, player) - }) - }) - } - - function queueAll(items, mode, player) { - if (items.length) { - if (!player.isLocalPlayer) return void("next" === mode ? player.queueNext({ - items: items - }) : player.queue({ - items: items - })); - if (player && !enableLocalPlaylistManagement(player)) { - var apiClient = connectionManager.getApiClient(items[0].ServerId); - return void player.getDeviceProfile(items[0]).then(function(profile) { - setStreamUrls(items, profile, self.getMaxStreamingBitrate(player), apiClient, 0).then(function() { - "next" === mode ? player.queueNext(items) : player.queue(items) - }) - }) - } - "next" === mode ? self._playQueueManager.queueNext(items) : self._playQueueManager.queue(items) - } - } - - function onPlayerProgressInterval() { - sendProgressUpdate(this, "timeupdate") - } - - function startPlaybackProgressTimer(player) { - stopPlaybackProgressTimer(player), player._progressInterval = setInterval(onPlayerProgressInterval.bind(player), 1e4) - } - - function stopPlaybackProgressTimer(player) { - player._progressInterval && (clearInterval(player._progressInterval), player._progressInterval = null) - } - - function onPlaybackStarted(player, playOptions, streamInfo, mediaSource) { - if (!player) throw new Error("player cannot be null"); - setCurrentPlayerInternal(player); - var playerData = getPlayerData(player); - playerData.streamInfo = streamInfo, streamInfo.playbackStartTimeTicks = 1e4 * (new Date).getTime(), mediaSource ? (playerData.audioStreamIndex = mediaSource.DefaultAudioStreamIndex, playerData.subtitleStreamIndex = mediaSource.DefaultSubtitleStreamIndex) : (playerData.audioStreamIndex = null, playerData.subtitleStreamIndex = null), self._playNextAfterEnded = !0; - var isFirstItem = playOptions.isFirstItem, - fullscreen = playOptions.fullscreen, - state = self.getPlayerState(player, streamInfo.item, streamInfo.mediaSource); - reportPlayback(self, state, player, !0, state.NowPlayingItem.ServerId, "reportPlaybackStart"), state.IsFirstItem = isFirstItem, state.IsFullscreen = fullscreen, events.trigger(player, "playbackstart", [state]), events.trigger(self, "playbackstart", [player, state]), streamInfo.started = !0, startPlaybackProgressTimer(player) - } - - function onPlaybackStartedFromSelfManagingPlayer(e, item, mediaSource) { - var player = this; - setCurrentPlayerInternal(player); - var playOptions = item.playOptions || {}, - isFirstItem = playOptions.isFirstItem, - fullscreen = playOptions.fullscreen; - playOptions.isFirstItem = !1; - var playerData = getPlayerData(player); - playerData.streamInfo = {}; - var streamInfo = playerData.streamInfo; - streamInfo.playbackStartTimeTicks = 1e4 * (new Date).getTime(); - var state = self.getPlayerState(player, item, mediaSource); - reportPlayback(self, state, player, !0, state.NowPlayingItem.ServerId, "reportPlaybackStart"), state.IsFirstItem = isFirstItem, state.IsFullscreen = fullscreen, events.trigger(player, "playbackstart", [state]), events.trigger(self, "playbackstart", [player, state]), streamInfo.started = !0, startPlaybackProgressTimer(player) - } - - function onPlaybackStoppedFromSelfManagingPlayer(e, playerStopInfo) { - var player = this; - stopPlaybackProgressTimer(player); - var state = self.getPlayerState(player, playerStopInfo.item, playerStopInfo.mediaSource), - nextItem = playerStopInfo.nextItem, - nextMediaType = playerStopInfo.nextMediaType, - playbackStopInfo = { - player: player, - state: state, - nextItem: nextItem ? nextItem.item : null, - nextMediaType: nextMediaType - }; - state.NextMediaType = nextMediaType, getPlayerData(player).streamInfo.ended = !0, isServerItem(playerStopInfo.item) && (state.PlayState.PositionTicks = 1e4 * (playerStopInfo.positionMs || 0), reportPlayback(self, state, player, !0, playerStopInfo.item.ServerId, "reportPlaybackStopped")), state.NextItem = playbackStopInfo.nextItem, events.trigger(player, "playbackstop", [state]), events.trigger(self, "playbackstop", [playbackStopInfo]); - var nextItemPlayOptions = nextItem ? nextItem.item.playOptions || getDefaultPlayOptions() : getDefaultPlayOptions(); - (nextItem ? getPlayer(nextItem.item, nextItemPlayOptions) : null) !== player && (destroyPlayer(player), removeCurrentPlayer(player)) - } - - function enablePlaybackRetryWithTranscoding(streamInfo, errorType, currentlyPreventsVideoStreamCopy, currentlyPreventsAudioStreamCopy) { - return !(!streamInfo.mediaSource.SupportsTranscoding || currentlyPreventsVideoStreamCopy && currentlyPreventsAudioStreamCopy) - } - - function onPlaybackError(e, error) { - var player = this; - error = error || {}; - var errorType = error.type; - console.log("playbackmanager playback error type: " + (errorType || "")); - var streamInfo = error.streamInfo || getPlayerData(player).streamInfo; - if (streamInfo) { - var currentlyPreventsVideoStreamCopy = -1 !== streamInfo.url.toLowerCase().indexOf("allowvideostreamcopy=false"), - currentlyPreventsAudioStreamCopy = -1 !== streamInfo.url.toLowerCase().indexOf("allowaudiostreamcopy=false"); - if (enablePlaybackRetryWithTranscoding(streamInfo, errorType, currentlyPreventsVideoStreamCopy, currentlyPreventsAudioStreamCopy)) { - return void changeStream(player, getCurrentTicks(player) || streamInfo.playerStartPositionTicks, { - EnableDirectPlay: !1, - EnableDirectStream: !1, - AllowVideoStreamCopy: !1, - AllowAudioStreamCopy: !currentlyPreventsAudioStreamCopy && !currentlyPreventsVideoStreamCopy && null - }, !0) - } - } - onPlaybackStopped.call(player, e, "NoCompatibleStream") - } - - function onPlaybackStopped(e, displayErrorCode) { - var player = this; - if (!getPlayerData(player).isChangingStream) { - stopPlaybackProgressTimer(player); - var state = self.getPlayerState(player), - streamInfo = getPlayerData(player).streamInfo, - nextItem = self._playNextAfterEnded ? self._playQueueManager.getNextItemInfo() : null, - nextMediaType = nextItem ? nextItem.item.MediaType : null, - playbackStopInfo = { - player: player, - state: state, - nextItem: nextItem ? nextItem.item : null, - nextMediaType: nextMediaType - }; - state.NextMediaType = nextMediaType, isServerItem(streamInfo.item) && (!1 === player.supportsProgress && state.PlayState && !state.PlayState.PositionTicks && (state.PlayState.PositionTicks = streamInfo.item.RunTimeTicks), streamInfo.ended = !0, reportPlayback(self, state, player, !0, streamInfo.item.ServerId, "reportPlaybackStopped")), state.NextItem = playbackStopInfo.nextItem, nextItem || self._playQueueManager.reset(), events.trigger(player, "playbackstop", [state]), events.trigger(self, "playbackstop", [playbackStopInfo]); - var nextItemPlayOptions = nextItem ? nextItem.item.playOptions || getDefaultPlayOptions() : getDefaultPlayOptions(); - (nextItem ? getPlayer(nextItem.item, nextItemPlayOptions) : null) !== player && (destroyPlayer(player), removeCurrentPlayer(player)), displayErrorCode && "string" == typeof displayErrorCode ? showPlaybackInfoErrorMessage(self, displayErrorCode, nextItem) : nextItem && self.nextTrack() - } - } - - function onPlaybackChanging(activePlayer, newPlayer, newItem) { - var promise, state = self.getPlayerState(activePlayer), - serverId = self.currentItem(activePlayer).ServerId; - return stopPlaybackProgressTimer(activePlayer), unbindStopped(activePlayer), promise = activePlayer === newPlayer ? activePlayer.stop(!1) : activePlayer.stop(!0), promise.then(function() { - bindStopped(activePlayer), enableLocalPlaylistManagement(activePlayer) && reportPlayback(self, state, activePlayer, !0, serverId, "reportPlaybackStopped"), events.trigger(self, "playbackstop", [{ - player: activePlayer, - state: state, - nextItem: newItem, - nextMediaType: newItem.MediaType - }]) - }) - } - - function bindStopped(player) { - enableLocalPlaylistManagement(player) && (events.off(player, "stopped", onPlaybackStopped), events.on(player, "stopped", onPlaybackStopped)) - } - - function onPlaybackTimeUpdate(e) { - sendProgressUpdate(this, "timeupdate") - } - - function onPlaybackPause(e) { - sendProgressUpdate(this, "pause") - } - - function onPlaybackUnpause(e) { - sendProgressUpdate(this, "unpause") - } - - function onPlaybackVolumeChange(e) { - sendProgressUpdate(this, "volumechange") - } - - function onRepeatModeChange(e) { - sendProgressUpdate(this, "repeatmodechange") - } - - function onPlaylistItemMove(e) { - sendProgressUpdate(this, "playlistitemmove", !0) - } - - function onPlaylistItemRemove(e) { - sendProgressUpdate(this, "playlistitemremove", !0) - } - - function onPlaylistItemAdd(e) { - sendProgressUpdate(this, "playlistitemadd", !0) - } - - function unbindStopped(player) { - events.off(player, "stopped", onPlaybackStopped) - } - - function initLegacyVolumeMethods(player) { - player.getVolume = function() { - return player.volume() - }, player.setVolume = function(val) { - return player.volume(val) - } - } - - function initMediaPlayer(player) { - players.push(player), players.sort(function(a, b) { - return (a.priority || 0) - (b.priority || 0) - }), !1 !== player.isLocalPlayer && (player.isLocalPlayer = !0), player.currentState = {}, player.getVolume && player.setVolume || initLegacyVolumeMethods(player), enableLocalPlaylistManagement(player) ? (events.on(player, "error", onPlaybackError), events.on(player, "timeupdate", onPlaybackTimeUpdate), events.on(player, "pause", onPlaybackPause), events.on(player, "unpause", onPlaybackUnpause), events.on(player, "volumechange", onPlaybackVolumeChange), events.on(player, "repeatmodechange", onRepeatModeChange), events.on(player, "playlistitemmove", onPlaylistItemMove), events.on(player, "playlistitemremove", onPlaylistItemRemove), events.on(player, "playlistitemadd", onPlaylistItemAdd)) : player.isLocalPlayer && (events.on(player, "itemstarted", onPlaybackStartedFromSelfManagingPlayer), events.on(player, "itemstopped", onPlaybackStoppedFromSelfManagingPlayer), events.on(player, "timeupdate", onPlaybackTimeUpdate), events.on(player, "pause", onPlaybackPause), events.on(player, "unpause", onPlaybackUnpause), events.on(player, "volumechange", onPlaybackVolumeChange), events.on(player, "repeatmodechange", onRepeatModeChange), events.on(player, "playlistitemmove", onPlaylistItemMove), events.on(player, "playlistitemremove", onPlaylistItemRemove), events.on(player, "playlistitemadd", onPlaylistItemAdd)), player.isLocalPlayer && bindToFullscreenChange(player), bindStopped(player) - } - - function sendProgressUpdate(player, progressEventName, reportPlaylist) { - if (!player) throw new Error("player cannot be null"); - var state = self.getPlayerState(player); - if (state.NowPlayingItem) { - var serverId = state.NowPlayingItem.ServerId, - streamInfo = getPlayerData(player).streamInfo; - streamInfo && streamInfo.started && !streamInfo.ended && reportPlayback(self, state, player, reportPlaylist, serverId, "reportPlaybackProgress", progressEventName), streamInfo && streamInfo.liveStreamId && (new Date).getTime() - (streamInfo.lastMediaInfoQuery || 0) >= 6e5 && getLiveStreamMediaInfo(player, streamInfo, self.currentMediaSource(player), streamInfo.liveStreamId, serverId) - } - } - - function getLiveStreamMediaInfo(player, streamInfo, mediaSource, liveStreamId, serverId) { - console.log("getLiveStreamMediaInfo"), streamInfo.lastMediaInfoQuery = (new Date).getTime(), connectionManager.getApiClient(serverId).isMinServerVersion("3.2.70.7") && connectionManager.getApiClient(serverId).getLiveStreamMediaInfo(liveStreamId).then(function(info) { - mediaSource.MediaStreams = info.MediaStreams, events.trigger(player, "mediastreamschange") - }, function() {}) - } - var currentTargetInfo, lastLocalPlayer, self = this, - players = [], - currentPairingId = null; - this._playNextAfterEnded = !0; + this._playNextAfterEnded = true; var playerStates = {}; - this._playQueueManager = new PlayQueueManager, self.currentItem = function(player) { - if (!player) throw new Error("player cannot be null"); - if (player.currentItem) return player.currentItem(); + + this._playQueueManager = new PlayQueueManager(); + + self.currentItem = function (player) { + + if (!player) { + throw new Error('player cannot be null'); + } + + if (player.currentItem) { + return player.currentItem(); + } + var data = getPlayerData(player); - return data.streamInfo ? data.streamInfo.item : null - }, self.currentMediaSource = function(player) { - if (!player) throw new Error("player cannot be null"); - if (player.currentMediaSource) return player.currentMediaSource(); + return data.streamInfo ? data.streamInfo.item : null; + }; + + self.currentMediaSource = function (player) { + + if (!player) { + throw new Error('player cannot be null'); + } + + if (player.currentMediaSource) { + return player.currentMediaSource(); + } + var data = getPlayerData(player); - return data.streamInfo ? data.streamInfo.mediaSource : null - }, self.playMethod = function(player) { - if (!player) throw new Error("player cannot be null"); - if (player.playMethod) return player.playMethod(); + return data.streamInfo ? data.streamInfo.mediaSource : null; + }; + + self.playMethod = function (player) { + + if (!player) { + throw new Error('player cannot be null'); + } + + if (player.playMethod) { + return player.playMethod(); + } + var data = getPlayerData(player); - return data.streamInfo ? data.streamInfo.playMethod : null - }, self.playSessionId = function(player) { - if (!player) throw new Error("player cannot be null"); - if (player.playSessionId) return player.playSessionId(); + return data.streamInfo ? data.streamInfo.playMethod : null; + }; + + self.playSessionId = function (player) { + + if (!player) { + throw new Error('player cannot be null'); + } + + if (player.playSessionId) { + return player.playSessionId(); + } + var data = getPlayerData(player); - return data.streamInfo ? data.streamInfo.playSessionId : null - }, self.getPlayerInfo = function() { + return data.streamInfo ? data.streamInfo.playSessionId : null; + }; + + self.getPlayerInfo = function () { + var player = self._currentPlayer; - if (!player) return null; + + if (!player) { + return null; + } + var target = currentTargetInfo || {}; + return { + name: player.name, isLocalPlayer: player.isLocalPlayer, id: target.id, deviceName: target.deviceName, playableMediaTypes: target.playableMediaTypes, supportedCommands: target.supportedCommands + }; + }; + + self.setActivePlayer = function (player, targetInfo) { + + if (player === 'localplayer' || player.name === 'localplayer') { + if (self._currentPlayer && self._currentPlayer.isLocalPlayer) { + return; + } + setCurrentPlayerInternal(null, null); + return; } - }, self.setActivePlayer = function(player, targetInfo) { - if ("localplayer" === player || "localplayer" === player.name) { - if (self._currentPlayer && self._currentPlayer.isLocalPlayer) return; - return void setCurrentPlayerInternal(null, null) + + if (typeof (player) === 'string') { + player = players.filter(function (p) { + return p.name === player; + })[0]; } - if ("string" == typeof player && (player = players.filter(function(p) { - return p.name === player - })[0]), !player) throw new Error("null player"); - setCurrentPlayerInternal(player, targetInfo) - }, self.trySetActivePlayer = function(player, targetInfo) { - if ("localplayer" === player || "localplayer" === player.name) return void(self._currentPlayer && self._currentPlayer.isLocalPlayer); - if ("string" == typeof player && (player = players.filter(function(p) { - return p.name === player - })[0]), !player) throw new Error("null player"); - if (currentPairingId !== targetInfo.id) { - currentPairingId = targetInfo.id; - var promise = player.tryPair ? player.tryPair(targetInfo) : Promise.resolve(); - events.trigger(self, "pairing"), promise.then(function() { - events.trigger(self, "paired"), setCurrentPlayerInternal(player, targetInfo) - }, function() { - events.trigger(self, "pairerror"), currentPairingId === targetInfo.id && (currentPairingId = null) - }) + + if (!player) { + throw new Error('null player'); } - }, self.getTargets = function() { + + setCurrentPlayerInternal(player, targetInfo); + }; + + self.trySetActivePlayer = function (player, targetInfo) { + + if (player === 'localplayer' || player.name === 'localplayer') { + if (self._currentPlayer && self._currentPlayer.isLocalPlayer) { + return; + } + return; + } + + if (typeof (player) === 'string') { + player = players.filter(function (p) { + return p.name === player; + })[0]; + } + + if (!player) { + throw new Error('null player'); + } + + if (currentPairingId === targetInfo.id) { + return; + } + + currentPairingId = targetInfo.id; + + var promise = player.tryPair ? + player.tryPair(targetInfo) : + Promise.resolve(); + + events.trigger(self, 'pairing'); + + promise.then(function () { + + events.trigger(self, 'paired'); + + setCurrentPlayerInternal(player, targetInfo); + }, function () { + + events.trigger(self, 'pairerror'); + + if (currentPairingId === targetInfo.id) { + currentPairingId = null; + } + }); + }; + + self.getTargets = function () { + var promises = players.filter(displayPlayerIndividually).map(getPlayerTargets); - return Promise.all(promises).then(function(responses) { - return connectionManager.currentApiClient().getCurrentUser().then(function(user) { + + return Promise.all(promises).then(function (responses) { + + return connectionManager.currentApiClient().getCurrentUser().then(function (user) { + var targets = []; + targets.push({ - name: globalize.translate("sharedcomponents#HeaderMyDevice"), - id: "localplayer", - playerName: "localplayer", - playableMediaTypes: ["Audio", "Video", "Game", "Photo", "Book"], - isLocalPlayer: !0, + name: globalize.translate('sharedcomponents#HeaderMyDevice'), + id: 'localplayer', + playerName: 'localplayer', + playableMediaTypes: ['Audio', 'Video', 'Game', 'Photo', 'Book'], + isLocalPlayer: true, supportedCommands: self.getSupportedCommands({ - isLocalPlayer: !0 + isLocalPlayer: true }), user: user }); - for (var i = 0; i < responses.length; i++) - for (var subTargets = responses[i], j = 0; j < subTargets.length; j++) targets.push(subTargets[j]); - return targets = targets.sort(sortPlayerTargets) - }) - }) - }, self.getPlaylist = function(player) { - return player = player || self._currentPlayer, player && !enableLocalPlaylistManagement(player) ? player.getPlaylistSync ? Promise.resolve(player.getPlaylistSync()) : player.getPlaylist() : Promise.resolve(self._playQueueManager.getPlaylist()) - }, self.isPlaying = function(player) { - return player = player || self._currentPlayer, player && player.isPlaying ? player.isPlaying() : null != player && null != player.currentSrc() - }, self.isPlayingMediaType = function(mediaType, player) { - if ((player = player || self._currentPlayer) && player.isPlaying) return player.isPlaying(mediaType); + + for (var i = 0; i < responses.length; i++) { + + var subTargets = responses[i]; + + for (var j = 0; j < subTargets.length; j++) { + + targets.push(subTargets[j]); + } + } + + targets = targets.sort(sortPlayerTargets); + + return targets; + }); + }); + }; + + function getCurrentSubtitleStream(player) { + + if (!player) { + throw new Error('player cannot be null'); + } + + var index = getPlayerData(player).subtitleStreamIndex; + + if (index == null || index === -1) { + return null; + } + + return getSubtitleStream(player, index); + } + + function getSubtitleStream(player, index) { + return self.subtitleTracks(player).filter(function (s) { + return s.Type === 'Subtitle' && s.Index === index; + })[0]; + } + + self.getPlaylist = function (player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + + if (player.getPlaylistSync) { + return Promise.resolve(player.getPlaylistSync()); + } + + return player.getPlaylist(); + } + + return Promise.resolve(self._playQueueManager.getPlaylist()); + }; + + function removeCurrentPlayer(player) { + var previousPlayer = self._currentPlayer; + + if (!previousPlayer || player.id === previousPlayer.id) { + setCurrentPlayerInternal(null); + } + } + + function setCurrentPlayerInternal(player, targetInfo) { + + var previousPlayer = self._currentPlayer; + var previousTargetInfo = currentTargetInfo; + + if (player && !targetInfo && player.isLocalPlayer) { + targetInfo = createTarget(self, player); + } + + if (player && !targetInfo) { + throw new Error('targetInfo cannot be null'); + } + + currentPairingId = null; + self._currentPlayer = player; + currentTargetInfo = targetInfo; + + if (targetInfo) { + console.log('Active player: ' + JSON.stringify(targetInfo)); + } + + if (player && player.isLocalPlayer) { + lastLocalPlayer = player; + } + + if (previousPlayer) { + self.endPlayerUpdates(previousPlayer); + } + + if (player) { + self.beginPlayerUpdates(player); + } + + triggerPlayerChange(self, player, targetInfo, previousPlayer, previousTargetInfo); + } + + self.isPlaying = function (player) { + + player = player || self._currentPlayer; + + if (player) { + if (player.isPlaying) { + return player.isPlaying(); + } + } + + return player != null && player.currentSrc() != null; + }; + + self.isPlayingMediaType = function (mediaType, player) { + player = player || self._currentPlayer; + + if (player) { + if (player.isPlaying) { + return player.isPlaying(mediaType); + } + } + if (self.isPlaying(player)) { - return getPlayerData(player).streamInfo.mediaType === mediaType + var playerData = getPlayerData(player); + + return playerData.streamInfo.mediaType === mediaType; } - return !1 - }, self.isPlayingLocally = function(mediaTypes, player) { - return !(!(player = player || self._currentPlayer) || !player.isLocalPlayer) && mediaTypes.filter(function(mediaType) { - return self.isPlayingMediaType(mediaType, player) - }).length > 0 - }, self.isPlayingVideo = function(player) { - return self.isPlayingMediaType("Video", player) - }, self.isPlayingAudio = function(player) { - return self.isPlayingMediaType("Audio", player) - }, self.getPlayers = function() { - return players - }, self.canPlay = function(item) { + + return false; + }; + + self.isPlayingLocally = function (mediaTypes, player) { + + player = player || self._currentPlayer; + + if (!player || !player.isLocalPlayer) { + return false; + } + + return mediaTypes.filter(function (mediaType) { + + return self.isPlayingMediaType(mediaType, player); + + }).length > 0; + }; + + self.isPlayingVideo = function (player) { + return self.isPlayingMediaType('Video', player); + }; + + self.isPlayingAudio = function (player) { + return self.isPlayingMediaType('Audio', player); + }; + + self.getPlayers = function () { + + return players; + }; + + function getDefaultPlayOptions() { + return { + fullscreen: true + }; + } + + self.canPlay = function (item) { + var itemType = item.Type; - if ("PhotoAlbum" === itemType || "MusicGenre" === itemType || "Season" === itemType || "Series" === itemType || "BoxSet" === itemType || "MusicAlbum" === itemType || "MusicArtist" === itemType || "Playlist" === itemType) return !0; - if ("Virtual" === item.LocationType && "Program" !== itemType) return !1; - if ("Program" === itemType) { - if (!item.EndDate || !item.StartDate) return !1; - if ((new Date).getTime() > datetime.parseISO8601Date(item.EndDate).getTime() || (new Date).getTime() < datetime.parseISO8601Date(item.StartDate).getTime()) return !1 + + if (itemType === "PhotoAlbum" || itemType === "MusicGenre" || itemType === "Season" || itemType === "Series" || itemType === "BoxSet" || itemType === "MusicAlbum" || itemType === "MusicArtist" || itemType === "Playlist") { + return true; } - return null != getPlayer(item, getDefaultPlayOptions()) - }, self.toggleAspectRatio = function(player) { - if (player = player || self._currentPlayer) { - for (var current = self.getAspectRatio(player), supported = self.getSupportedAspectRatios(player), index = -1, i = 0, length = supported.length; i < length; i++) + + if (item.LocationType === "Virtual") { + if (itemType !== "Program") { + return false; + } + } + + if (itemType === "Program") { + + if (!item.EndDate || !item.StartDate) { + return false; + } + + if (new Date().getTime() > datetime.parseISO8601Date(item.EndDate).getTime() || new Date().getTime() < datetime.parseISO8601Date(item.StartDate).getTime()) { + return false; + } + } + + //var mediaType = item.MediaType; + return getPlayer(item, getDefaultPlayOptions()) != null; + }; + + self.toggleAspectRatio = function (player) { + + player = player || self._currentPlayer; + + if (player) { + var current = self.getAspectRatio(player); + + var supported = self.getSupportedAspectRatios(player); + + var index = -1; + for (var i = 0, length = supported.length; i < length; i++) { if (supported[i].id === current) { index = i; - break - } index++, index >= supported.length && (index = 0), self.setAspectRatio(supported[index].id, player) + break; + } + } + + index++; + if (index >= supported.length) { + index = 0; + } + + self.setAspectRatio(supported[index].id, player); } - }, self.setAspectRatio = function(val, player) { - (player = player || self._currentPlayer) && player.setAspectRatio && player.setAspectRatio(val) - }, self.getSupportedAspectRatios = function(player) { - return player = player || self._currentPlayer, player && player.getSupportedAspectRatios ? player.getSupportedAspectRatios() : [] - }, self.getAspectRatio = function(player) { - if ((player = player || self._currentPlayer) && player.getAspectRatio) return player.getAspectRatio() }; + + self.setAspectRatio = function (val, player) { + + player = player || self._currentPlayer; + + if (player && player.setAspectRatio) { + + player.setAspectRatio(val); + } + }; + + self.getSupportedAspectRatios = function (player) { + + player = player || self._currentPlayer; + + if (player && player.getSupportedAspectRatios) { + return player.getSupportedAspectRatios(); + } + + return []; + }; + + self.getAspectRatio = function (player) { + + player = player || self._currentPlayer; + + if (player && player.getAspectRatio) { + return player.getAspectRatio(); + } + }; + var brightnessOsdLoaded; - self.setBrightness = function(val, player) { - (player = player || self._currentPlayer) && (brightnessOsdLoaded || (brightnessOsdLoaded = !0, require(["brightnessOsd"])), player.setBrightness(val)) - }, self.getBrightness = function(player) { - if (player = player || self._currentPlayer) return player.getBrightness() - }, self.setVolume = function(val, player) { - (player = player || self._currentPlayer) && player.setVolume(val) - }, self.getVolume = function(player) { - if (player = player || self._currentPlayer) return player.getVolume() - }, self.volumeUp = function(player) { - (player = player || self._currentPlayer) && player.volumeUp() - }, self.volumeDown = function(player) { - (player = player || self._currentPlayer) && player.volumeDown() - }, self.changeAudioStream = function(player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.changeAudioStream(); + self.setBrightness = function (val, player) { + + player = player || self._currentPlayer; + if (player) { - var i, length, currentMediaSource = self.currentMediaSource(player), - mediaStreams = []; - for (i = 0, length = currentMediaSource.MediaStreams.length; i < length; i++) "Audio" === currentMediaSource.MediaStreams[i].Type && mediaStreams.push(currentMediaSource.MediaStreams[i]); - if (!(mediaStreams.length <= 1)) { - var currentStreamIndex = self.getAudioStreamIndex(player), - indexInList = -1; - for (i = 0, length = mediaStreams.length; i < length; i++) - if (mediaStreams[i].Index === currentStreamIndex) { - indexInList = i; - break - } var nextIndex = indexInList + 1; - nextIndex >= mediaStreams.length && (nextIndex = 0), nextIndex = -1 === nextIndex ? -1 : mediaStreams[nextIndex].Index, self.setAudioStreamIndex(nextIndex, player) + + if (!brightnessOsdLoaded) { + brightnessOsdLoaded = true; + // TODO: Have this trigger an event instead to get the osd out of here + require(['brightnessOsd']); + } + player.setBrightness(val); + } + }; + + self.getBrightness = function (player) { + + player = player || self._currentPlayer; + + if (player) { + return player.getBrightness(); + } + }; + + self.setVolume = function (val, player) { + + player = player || self._currentPlayer; + + if (player) { + player.setVolume(val); + } + }; + + self.getVolume = function (player) { + + player = player || self._currentPlayer; + + if (player) { + return player.getVolume(); + } + }; + + self.volumeUp = function (player) { + + player = player || self._currentPlayer; + + if (player) { + player.volumeUp(); + } + }; + + self.volumeDown = function (player) { + + player = player || self._currentPlayer; + + if (player) { + player.volumeDown(); + } + }; + + self.changeAudioStream = function (player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.changeAudioStream(); + } + + if (!player) { + return; + } + + var currentMediaSource = self.currentMediaSource(player); + var mediaStreams = []; + var i, length; + for (i = 0, length = currentMediaSource.MediaStreams.length; i < length; i++) { + if (currentMediaSource.MediaStreams[i].Type === 'Audio') { + mediaStreams.push(currentMediaSource.MediaStreams[i]); } } - }, self.changeSubtitleStream = function(player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.changeSubtitleStream(); - if (player) { - var i, length, currentMediaSource = self.currentMediaSource(player), - mediaStreams = []; - for (i = 0, length = currentMediaSource.MediaStreams.length; i < length; i++) "Subtitle" === currentMediaSource.MediaStreams[i].Type && mediaStreams.push(currentMediaSource.MediaStreams[i]); - if (mediaStreams.length) { - var currentStreamIndex = self.getSubtitleStreamIndex(player), - indexInList = -1; - for (i = 0, length = mediaStreams.length; i < length; i++) - if (mediaStreams[i].Index === currentStreamIndex) { - indexInList = i; - break - } var nextIndex = indexInList + 1; - nextIndex >= mediaStreams.length && (nextIndex = -1), nextIndex = -1 === nextIndex ? -1 : mediaStreams[nextIndex].Index, self.setSubtitleStreamIndex(nextIndex, player) + + // Nothing to change + if (mediaStreams.length <= 1) { + return; + } + + var currentStreamIndex = self.getAudioStreamIndex(player); + var indexInList = -1; + for (i = 0, length = mediaStreams.length; i < length; i++) { + if (mediaStreams[i].Index === currentStreamIndex) { + indexInList = i; + break; } } - }, self.getAudioStreamIndex = function(player) { - return player = player || self._currentPlayer, player && !enableLocalPlaylistManagement(player) ? player.getAudioStreamIndex() : getPlayerData(player).audioStreamIndex - }, self.setAudioStreamIndex = function(index, player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.setAudioStreamIndex(index); - "Transcode" !== self.playMethod(player) && player.canSetAudioStreamIndex() ? player.getDeviceProfile(self.currentItem(player)).then(function(profile) { - isAudioStreamSupported(self.currentMediaSource(player), index, profile) ? (player.setAudioStreamIndex(index), getPlayerData(player).audioStreamIndex = index) : (changeStream(player, getCurrentTicks(player), { - AudioStreamIndex: index - }), getPlayerData(player).audioStreamIndex = index) - }) : (changeStream(player, getCurrentTicks(player), { - AudioStreamIndex: index - }), getPlayerData(player).audioStreamIndex = index) - }, self.getMaxStreamingBitrate = function(player) { - if ((player = player || self._currentPlayer) && player.getMaxStreamingBitrate) return player.getMaxStreamingBitrate(); + + var nextIndex = indexInList + 1; + if (nextIndex >= mediaStreams.length) { + nextIndex = 0; + } + + nextIndex = nextIndex === -1 ? -1 : mediaStreams[nextIndex].Index; + + self.setAudioStreamIndex(nextIndex, player); + }; + + self.changeSubtitleStream = function (player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.changeSubtitleStream(); + } + + if (!player) { + return; + } + + var currentMediaSource = self.currentMediaSource(player); + var mediaStreams = []; + var i, length; + for (i = 0, length = currentMediaSource.MediaStreams.length; i < length; i++) { + if (currentMediaSource.MediaStreams[i].Type === 'Subtitle') { + mediaStreams.push(currentMediaSource.MediaStreams[i]); + } + } + + // No known streams, nothing to change + if (!mediaStreams.length) { + return; + } + + var currentStreamIndex = self.getSubtitleStreamIndex(player); + var indexInList = -1; + for (i = 0, length = mediaStreams.length; i < length; i++) { + if (mediaStreams[i].Index === currentStreamIndex) { + indexInList = i; + break; + } + } + + var nextIndex = indexInList + 1; + if (nextIndex >= mediaStreams.length) { + nextIndex = -1; + } + + nextIndex = nextIndex === -1 ? -1 : mediaStreams[nextIndex].Index; + + self.setSubtitleStreamIndex(nextIndex, player); + }; + + self.getAudioStreamIndex = function (player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.getAudioStreamIndex(); + } + + return getPlayerData(player).audioStreamIndex; + }; + + function isAudioStreamSupported(mediaSource, index, deviceProfile) { + + var mediaStream; + var i, length; + var mediaStreams = mediaSource.MediaStreams; + + for (i = 0, length = mediaStreams.length; i < length; i++) { + if (mediaStreams[i].Type === 'Audio' && mediaStreams[i].Index === index) { + mediaStream = mediaStreams[i]; + break; + } + } + + if (!mediaStream) { + return false; + } + + var codec = (mediaStream.Codec || '').toLowerCase(); + + if (!codec) { + return false; + } + + var profiles = deviceProfile.DirectPlayProfiles || []; + + return profiles.filter(function (p) { + + if (p.Type === 'Video') { + + if (!p.AudioCodec) { + return true; + } + + // This is an exclusion filter + if (p.AudioCodec.indexOf('-') === 0) { + return p.AudioCodec.toLowerCase().indexOf(codec) === -1; + } + + return p.AudioCodec.toLowerCase().indexOf(codec) !== -1; + } + + return false; + + }).length > 0; + } + + self.setAudioStreamIndex = function (index, player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.setAudioStreamIndex(index); + } + + if (self.playMethod(player) === 'Transcode' || !player.canSetAudioStreamIndex()) { + + changeStream(player, getCurrentTicks(player), { AudioStreamIndex: index }); + getPlayerData(player).audioStreamIndex = index; + + } else { + + // See if the player supports the track without transcoding + player.getDeviceProfile(self.currentItem(player)).then(function (profile) { + + if (isAudioStreamSupported(self.currentMediaSource(player), index, profile)) { + player.setAudioStreamIndex(index); + getPlayerData(player).audioStreamIndex = index; + } + else { + changeStream(player, getCurrentTicks(player), { AudioStreamIndex: index }); + getPlayerData(player).audioStreamIndex = index; + } + }); + } + }; + + function getSavedMaxStreamingBitrate(apiClient, mediaType) { + + if (!apiClient) { + // This should hopefully never happen + apiClient = connectionManager.currentApiClient(); + } + + var endpointInfo = apiClient.getSavedEndpointInfo() || {}; + + return appSettings.maxStreamingBitrate(endpointInfo.IsInNetwork, mediaType); + } + + self.getMaxStreamingBitrate = function (player) { + + player = player || self._currentPlayer; + if (player && player.getMaxStreamingBitrate) { + return player.getMaxStreamingBitrate(); + } + var playerData = getPlayerData(player); - if (playerData.maxStreamingBitrate) return playerData.maxStreamingBitrate; - var mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null, - currentItem = self.currentItem(player); - return getSavedMaxStreamingBitrate(currentItem ? connectionManager.getApiClient(currentItem.ServerId) : connectionManager.currentApiClient(), mediaType) - }, self.enableAutomaticBitrateDetection = function(player) { - if ((player = player || self._currentPlayer) && player.enableAutomaticBitrateDetection) return player.enableAutomaticBitrateDetection(); - var playerData = getPlayerData(player), - mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null, - currentItem = self.currentItem(player), - apiClient = currentItem ? connectionManager.getApiClient(currentItem.ServerId) : connectionManager.currentApiClient(), - endpointInfo = apiClient.getSavedEndpointInfo() || {}; - return appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType) - }, self.setMaxStreamingBitrate = function(options, player) { - if ((player = player || self._currentPlayer) && player.setMaxStreamingBitrate) return player.setMaxStreamingBitrate(options); + + if (playerData.maxStreamingBitrate) { + return playerData.maxStreamingBitrate; + } + + var mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null; + var currentItem = self.currentItem(player); + + var apiClient = currentItem ? connectionManager.getApiClient(currentItem.ServerId) : connectionManager.currentApiClient(); + return getSavedMaxStreamingBitrate(apiClient, mediaType); + }; + + self.enableAutomaticBitrateDetection = function (player) { + + player = player || self._currentPlayer; + if (player && player.enableAutomaticBitrateDetection) { + return player.enableAutomaticBitrateDetection(); + } + + var playerData = getPlayerData(player); + var mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null; + var currentItem = self.currentItem(player); + + var apiClient = currentItem ? connectionManager.getApiClient(currentItem.ServerId) : connectionManager.currentApiClient(); + var endpointInfo = apiClient.getSavedEndpointInfo() || {}; + + return appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType); + }; + + self.setMaxStreamingBitrate = function (options, player) { + + player = player || self._currentPlayer; + if (player && player.setMaxStreamingBitrate) { + return player.setMaxStreamingBitrate(options); + } + var apiClient = connectionManager.getApiClient(self.currentItem(player).ServerId); - apiClient.getEndpointInfo().then(function(endpointInfo) { - var promise, playerData = getPlayerData(player), - mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null; - options.enableAutomaticBitrateDetection ? (appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType, !0), promise = apiClient.detectBitrate(!0)) : (appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType, !1), promise = Promise.resolve(options.maxBitrate)), promise.then(function(bitrate) { - appSettings.maxStreamingBitrate(endpointInfo.IsInNetwork, mediaType, bitrate), changeStream(player, getCurrentTicks(player), { + + apiClient.getEndpointInfo().then(function (endpointInfo) { + + var playerData = getPlayerData(player); + var mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null; + + var promise; + if (options.enableAutomaticBitrateDetection) { + appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType, true); + promise = apiClient.detectBitrate(true); + } else { + appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType, false); + promise = Promise.resolve(options.maxBitrate); + } + + promise.then(function (bitrate) { + + appSettings.maxStreamingBitrate(endpointInfo.IsInNetwork, mediaType, bitrate); + + changeStream(player, getCurrentTicks(player), { MaxStreamingBitrate: bitrate - }) - }) - }) - }, self.isFullscreen = function(player) { - return player = player || self._currentPlayer, !player.isLocalPlayer || player.isFullscreen ? player.isFullscreen() : fullscreenManager.isFullScreen() - }, self.toggleFullscreen = function(player) { - if (player = player || self._currentPlayer, !player.isLocalPlayer || player.toggleFulscreen) return player.toggleFulscreen(); - fullscreenManager.isFullScreen() ? fullscreenManager.exitFullscreen() : fullscreenManager.requestFullscreen() - }, self.togglePictureInPicture = function(player) { - return player = player || self._currentPlayer, player.togglePictureInPicture() - }, self.getSubtitleStreamIndex = function(player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.getSubtitleStreamIndex(); - if (!player) throw new Error("player cannot be null"); - return getPlayerData(player).subtitleStreamIndex - }, self.setSubtitleStreamIndex = function(index, player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.setSubtitleStreamIndex(index); - var currentStream = getCurrentSubtitleStream(player), - newStream = getSubtitleStream(player, index); - if (currentStream || newStream) { - var selectedTrackElementIndex = -1, - currentPlayMethod = self.playMethod(player); - currentStream && !newStream ? ("Encode" === getDeliveryMethod(currentStream) || "Embed" === getDeliveryMethod(currentStream) && "Transcode" === currentPlayMethod) && changeStream(player, getCurrentTicks(player), { - SubtitleStreamIndex: -1 - }) : !currentStream && newStream ? "External" === getDeliveryMethod(newStream) ? selectedTrackElementIndex = index : "Embed" === getDeliveryMethod(newStream) && "Transcode" !== currentPlayMethod ? selectedTrackElementIndex = index : changeStream(player, getCurrentTicks(player), { - SubtitleStreamIndex: index - }) : currentStream && newStream && ("External" === getDeliveryMethod(newStream) || "Embed" === getDeliveryMethod(newStream) && "Transcode" !== currentPlayMethod ? (selectedTrackElementIndex = index, "External" !== getDeliveryMethod(currentStream) && "Embed" !== getDeliveryMethod(currentStream) && changeStream(player, getCurrentTicks(player), { - SubtitleStreamIndex: -1 - })) : changeStream(player, getCurrentTicks(player), { - SubtitleStreamIndex: index - })), player.setSubtitleStreamIndex(selectedTrackElementIndex), getPlayerData(player).subtitleStreamIndex = index - } - }, self.seek = function(ticks, player) { - if (ticks = Math.max(0, ticks), (player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.isLocalPlayer ? player.seek((ticks || 0) / 1e4) : player.seek(ticks); - changeStream(player, ticks) - }, self.seekRelative = function(offsetTicks, player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player) && player.seekRelative) return player.isLocalPlayer ? player.seekRelative((ticks || 0) / 1e4) : player.seekRelative(ticks); - var ticks = getCurrentTicks(player) + offsetTicks; - return this.seek(ticks, player) - }, self.play = function(options) { - if (normalizePlayOptions(options), self._currentPlayer) { - if (!1 === options.enableRemotePlayers && !self._currentPlayer.isLocalPlayer) return Promise.reject(); - if (!self._currentPlayer.isLocalPlayer) return self._currentPlayer.play(options) - } - if (options.fullscreen && loading.show(), options.items) return translateItemsForPlayback(options.items, options).then(function(items) { - return playWithIntros(items, options) + }); + }); }); - if (!options.serverId) throw new Error("serverId required!"); - return getItemsForPlayback(options.serverId, { - Ids: options.ids.join(",") - }).then(function(result) { - return translateItemsForPlayback(result.Items, options).then(function(items) { - return playWithIntros(items, options) - }) - }) - }, self.getPlayerState = function(player, item, mediaSource) { - if (!(player = player || self._currentPlayer)) throw new Error("player cannot be null"); - if (!enableLocalPlaylistManagement(player) && player.getPlayerState) return player.getPlayerState(); - item = item || self.currentItem(player), mediaSource = mediaSource || self.currentMediaSource(player); + }; + + self.isFullscreen = function (player) { + + player = player || self._currentPlayer; + if (!player.isLocalPlayer || player.isFullscreen) { + return player.isFullscreen(); + } + + return fullscreenManager.isFullScreen(); + }; + + self.toggleFullscreen = function (player) { + + player = player || self._currentPlayer; + if (!player.isLocalPlayer || player.toggleFulscreen) { + return player.toggleFulscreen(); + } + + if (fullscreenManager.isFullScreen()) { + fullscreenManager.exitFullscreen(); + } else { + fullscreenManager.requestFullscreen(); + } + }; + + self.togglePictureInPicture = function (player) { + player = player || self._currentPlayer; + return player.togglePictureInPicture(); + }; + + self.getSubtitleStreamIndex = function (player) { + + player = player || self._currentPlayer; + + if (player && !enableLocalPlaylistManagement(player)) { + return player.getSubtitleStreamIndex(); + } + + if (!player) { + throw new Error('player cannot be null'); + } + + return getPlayerData(player).subtitleStreamIndex; + }; + + function getDeliveryMethod(subtitleStream) { + + // This will be null for internal subs for local items + if (subtitleStream.DeliveryMethod) { + return subtitleStream.DeliveryMethod; + } + + return subtitleStream.IsExternal ? 'External' : 'Embed'; + } + + self.setSubtitleStreamIndex = function (index, player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.setSubtitleStreamIndex(index); + } + + var currentStream = getCurrentSubtitleStream(player); + + var newStream = getSubtitleStream(player, index); + + if (!currentStream && !newStream) { + return; + } + + var selectedTrackElementIndex = -1; + + var currentPlayMethod = self.playMethod(player); + + if (currentStream && !newStream) { + + if (getDeliveryMethod(currentStream) === 'Encode' || (getDeliveryMethod(currentStream) === 'Embed' && currentPlayMethod === 'Transcode')) { + + // Need to change the transcoded stream to remove subs + changeStream(player, getCurrentTicks(player), { SubtitleStreamIndex: -1 }); + } + } + else if (!currentStream && newStream) { + + if (getDeliveryMethod(newStream) === 'External') { + selectedTrackElementIndex = index; + } else if (getDeliveryMethod(newStream) === 'Embed' && currentPlayMethod !== 'Transcode') { + selectedTrackElementIndex = index; + } else { + + // Need to change the transcoded stream to add subs + changeStream(player, getCurrentTicks(player), { SubtitleStreamIndex: index }); + } + } + else if (currentStream && newStream) { + + // Switching tracks + // We can handle this clientside if the new track is external or the new track is embedded and we're not transcoding + if (getDeliveryMethod(newStream) === 'External' || (getDeliveryMethod(newStream) === 'Embed' && currentPlayMethod !== 'Transcode')) { + selectedTrackElementIndex = index; + + // But in order to handle this client side, if the previous track is being added via transcoding, we'll have to remove it + if (getDeliveryMethod(currentStream) !== 'External' && getDeliveryMethod(currentStream) !== 'Embed') { + changeStream(player, getCurrentTicks(player), { SubtitleStreamIndex: -1 }); + } + } else { + + // Need to change the transcoded stream to add subs + changeStream(player, getCurrentTicks(player), { SubtitleStreamIndex: index }); + } + } + + player.setSubtitleStreamIndex(selectedTrackElementIndex); + + getPlayerData(player).subtitleStreamIndex = index; + }; + + self.seek = function (ticks, player) { + + ticks = Math.max(0, ticks); + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + + if (player.isLocalPlayer) { + return player.seek((ticks || 0) / 10000); + } else { + return player.seek(ticks); + } + } + + changeStream(player, ticks); + }; + + self.seekRelative = function (offsetTicks, player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player) && player.seekRelative) { + + if (player.isLocalPlayer) { + return player.seekRelative((ticks || 0) / 10000); + } else { + return player.seekRelative(ticks); + } + } + + var ticks = getCurrentTicks(player) + offsetTicks; + return this.seek(ticks, player); + }; + + // Returns true if the player can seek using native client-side seeking functions + function canPlayerSeek(player) { + + if (!player) { + throw new Error('player cannot be null'); + } + + var playerData = getPlayerData(player); + + var currentSrc = (playerData.streamInfo.url || '').toLowerCase(); + + if (currentSrc.indexOf('.m3u8') !== -1) { + return true; + } + + if (player.seekable) { + return player.seekable(); + } + + var isPlayMethodTranscode = self.playMethod(player) === 'Transcode'; + + if (isPlayMethodTranscode) { + return false; + } + + return player.duration(); + } + + function changeStream(player, ticks, params) { + + if (canPlayerSeek(player) && params == null) { + + player.currentTime(parseInt(ticks / 10000)); + return; + } + + params = params || {}; + + var liveStreamId = getPlayerData(player).streamInfo.liveStreamId; + var lastMediaInfoQuery = getPlayerData(player).streamInfo.lastMediaInfoQuery; + + var playSessionId = self.playSessionId(player); + + var currentItem = self.currentItem(player); + + player.getDeviceProfile(currentItem, { + + isRetry: params.EnableDirectPlay === false + + }).then(function (deviceProfile) { + + var audioStreamIndex = params.AudioStreamIndex == null ? getPlayerData(player).audioStreamIndex : params.AudioStreamIndex; + var subtitleStreamIndex = params.SubtitleStreamIndex == null ? getPlayerData(player).subtitleStreamIndex : params.SubtitleStreamIndex; + + var currentMediaSource = self.currentMediaSource(player); + var apiClient = connectionManager.getApiClient(currentItem.ServerId); + + if (ticks) { + ticks = parseInt(ticks); + } + + var maxBitrate = params.MaxStreamingBitrate || self.getMaxStreamingBitrate(player); + + var currentPlayOptions = currentItem.playOptions || {}; + + getPlaybackInfo(player, apiClient, currentItem, deviceProfile, maxBitrate, ticks, true, currentMediaSource.Id, audioStreamIndex, subtitleStreamIndex, liveStreamId, params.EnableDirectPlay, params.EnableDirectStream, params.AllowVideoStreamCopy, params.AllowAudioStreamCopy).then(function (result) { + + if (validatePlaybackInfoResult(self, result)) { + + currentMediaSource = result.MediaSources[0]; + + var streamInfo = createStreamInfo(apiClient, currentItem.MediaType, currentItem, currentMediaSource, ticks); + streamInfo.fullscreen = currentPlayOptions.fullscreen; + streamInfo.lastMediaInfoQuery = lastMediaInfoQuery; + + if (!streamInfo.url) { + showPlaybackInfoErrorMessage(self, 'NoCompatibleStream', true); + return; + } + + getPlayerData(player).subtitleStreamIndex = subtitleStreamIndex; + getPlayerData(player).audioStreamIndex = audioStreamIndex; + getPlayerData(player).maxStreamingBitrate = maxBitrate; + + changeStreamToUrl(apiClient, player, playSessionId, streamInfo); + } + }); + }); + } + + function changeStreamToUrl(apiClient, player, playSessionId, streamInfo, newPositionTicks) { + + var playerData = getPlayerData(player); + + playerData.isChangingStream = true; + + if (playerData.streamInfo && playSessionId) { + + apiClient.stopActiveEncodings(playSessionId).then(function () { + + // Stop the first transcoding afterwards because the player may still send requests to the original url + var afterSetSrc = function () { + + apiClient.stopActiveEncodings(playSessionId); + }; + setSrcIntoPlayer(apiClient, player, streamInfo).then(afterSetSrc, afterSetSrc); + }); + + } else { + setSrcIntoPlayer(apiClient, player, streamInfo); + } + } + + function setSrcIntoPlayer(apiClient, player, streamInfo) { + + return player.play(streamInfo).then(function () { + + var playerData = getPlayerData(player); + + playerData.isChangingStream = false; + playerData.streamInfo = streamInfo; + streamInfo.started = true; + streamInfo.ended = false; + + sendProgressUpdate(player, 'timeupdate'); + }, function (e) { + + var playerData = getPlayerData(player); + playerData.isChangingStream = false; + + onPlaybackError.call(player, e, { + type: 'mediadecodeerror', + streamInfo: streamInfo + }); + }); + } + + function translateItemsForPlayback(items, options) { + + var firstItem = items[0]; + var promise; + + var serverId = firstItem.ServerId; + + var queryOptions = options.queryOptions || {}; + + if (firstItem.Type === "Program") { + + promise = getItemsForPlayback(serverId, { + Ids: firstItem.ChannelId, + }); + } + else if (firstItem.Type === "Playlist") { + + promise = getItemsForPlayback(serverId, { + ParentId: firstItem.Id, + SortBy: options.shuffle ? 'Random' : null + }); + } + else if (firstItem.Type === "MusicArtist") { + + promise = getItemsForPlayback(serverId, { + ArtistIds: firstItem.Id, + Filters: "IsNotFolder", + Recursive: true, + SortBy: options.shuffle ? 'Random' : 'SortName', + MediaTypes: "Audio" + }); + + } + else if (firstItem.MediaType === "Photo") { + + promise = getItemsForPlayback(serverId, { + ParentId: firstItem.ParentId, + Filters: "IsNotFolder", + // Setting this to true may cause some incorrect sorting + Recursive: false, + SortBy: options.shuffle ? 'Random' : 'SortName', + MediaTypes: "Photo,Video", + Limit: 500 + + }).then(function (result) { + + var items = result.Items; + + var index = items.map(function (i) { + return i.Id; + + }).indexOf(firstItem.Id); + + if (index === -1) { + index = 0; + } + + options.startIndex = index; + + return Promise.resolve(result); + + }); + } + else if (firstItem.Type === "PhotoAlbum") { + + promise = getItemsForPlayback(serverId, { + ParentId: firstItem.Id, + Filters: "IsNotFolder", + // Setting this to true may cause some incorrect sorting + Recursive: false, + SortBy: options.shuffle ? 'Random' : 'SortName', + MediaTypes: "Photo,Video", + Limit: 1000 + + }); + } + else if (firstItem.Type === "MusicGenre") { + + promise = getItemsForPlayback(serverId, { + GenreIds: firstItem.Id, + Filters: "IsNotFolder", + Recursive: true, + SortBy: options.shuffle ? 'Random' : 'SortName', + MediaTypes: "Audio" + }); + } + else if (firstItem.IsFolder) { + + promise = getItemsForPlayback(serverId, mergePlaybackQueries({ + + ParentId: firstItem.Id, + Filters: "IsNotFolder", + Recursive: true, + // These are pre-sorted + SortBy: options.shuffle ? 'Random' : (['BoxSet'].indexOf(firstItem.Type) === -1 ? 'SortName' : null), + MediaTypes: "Audio,Video" + + }, queryOptions)); + } + else if (firstItem.Type === "Episode" && items.length === 1 && getPlayer(firstItem, options).supportsProgress !== false) { + + promise = new Promise(function (resolve, reject) { + var apiClient = connectionManager.getApiClient(firstItem.ServerId); + + apiClient.getCurrentUser().then(function (user) { + + if (!user.Configuration.EnableNextEpisodeAutoPlay || !firstItem.SeriesId) { + resolve(null); + return; + } + + apiClient.getEpisodes(firstItem.SeriesId, { + IsVirtualUnaired: false, + IsMissing: false, + UserId: apiClient.getCurrentUserId(), + Fields: "Chapters" + + }).then(function (episodesResult) { + + var foundItem = false; + episodesResult.Items = episodesResult.Items.filter(function (e) { + + if (foundItem) { + return true; + } + if (e.Id === firstItem.Id) { + foundItem = true; + return true; + } + + return false; + }); + episodesResult.TotalRecordCount = episodesResult.Items.length; + resolve(episodesResult); + }, reject); + }); + }); + } + + if (promise) { + return promise.then(function (result) { + + return result ? result.Items : items; + }); + } else { + return Promise.resolve(items); + } + } + + self.play = function (options) { + + normalizePlayOptions(options); + + if (self._currentPlayer) { + if (options.enableRemotePlayers === false && !self._currentPlayer.isLocalPlayer) { + return Promise.reject(); + } + + if (!self._currentPlayer.isLocalPlayer) { + return self._currentPlayer.play(options); + } + } + + if (options.fullscreen) { + loading.show(); + } + + if (options.items) { + + return translateItemsForPlayback(options.items, options).then(function (items) { + + return playWithIntros(items, options); + }); + + } else { + + if (!options.serverId) { + throw new Error('serverId required!'); + } + + return getItemsForPlayback(options.serverId, { + + Ids: options.ids.join(',') + + }).then(function (result) { + + return translateItemsForPlayback(result.Items, options).then(function (items) { + + return playWithIntros(items, options); + }); + + }); + } + }; + + function getPlayerData(player) { + + if (!player) { + throw new Error('player cannot be null'); + } + if (!player.name) { + throw new Error('player name cannot be null'); + } + var state = playerStates[player.name]; + + if (!state) { + playerStates[player.name] = {}; + state = playerStates[player.name]; + } + + return player; + } + + self.getPlayerState = function (player, item, mediaSource) { + + player = player || self._currentPlayer; + + if (!player) { + throw new Error('player cannot be null'); + } + + if (!enableLocalPlaylistManagement(player) && player.getPlayerState) { + return player.getPlayerState(); + } + + item = item || self.currentItem(player); + mediaSource = mediaSource || self.currentMediaSource(player); + var state = { PlayState: {} }; - return player && (state.PlayState.VolumeLevel = player.getVolume(), state.PlayState.IsMuted = player.isMuted(), state.PlayState.IsPaused = player.paused(), state.PlayState.RepeatMode = self.getRepeatMode(player), state.PlayState.MaxStreamingBitrate = self.getMaxStreamingBitrate(player), state.PlayState.PositionTicks = getCurrentTicks(player), state.PlayState.PlaybackStartTimeTicks = self.playbackStartTime(player), state.PlayState.SubtitleStreamIndex = self.getSubtitleStreamIndex(player), state.PlayState.AudioStreamIndex = self.getAudioStreamIndex(player), state.PlayState.BufferedRanges = self.getBufferedRanges(player), state.PlayState.PlayMethod = self.playMethod(player), mediaSource && (state.PlayState.LiveStreamId = mediaSource.LiveStreamId), state.PlayState.PlaySessionId = self.playSessionId(player), state.PlayState.PlaylistItemId = self.getCurrentPlaylistItemId(player)), mediaSource && (state.PlayState.MediaSourceId = mediaSource.Id, state.NowPlayingItem = { - RunTimeTicks: mediaSource.RunTimeTicks - }, state.PlayState.CanSeek = (mediaSource.RunTimeTicks || 0) > 0 || canPlayerSeek(player)), item && (state.NowPlayingItem = getNowPlayingItemForReporting(player, item, mediaSource)), state.MediaSource = mediaSource, state - }, self.duration = function(player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player) && !player.isLocalPlayer) return player.duration(); - if (!player) throw new Error("player cannot be null"); + + if (player) { + + state.PlayState.VolumeLevel = player.getVolume(); + state.PlayState.IsMuted = player.isMuted(); + state.PlayState.IsPaused = player.paused(); + state.PlayState.RepeatMode = self.getRepeatMode(player); + state.PlayState.MaxStreamingBitrate = self.getMaxStreamingBitrate(player); + + state.PlayState.PositionTicks = getCurrentTicks(player); + state.PlayState.PlaybackStartTimeTicks = self.playbackStartTime(player); + + state.PlayState.SubtitleStreamIndex = self.getSubtitleStreamIndex(player); + state.PlayState.AudioStreamIndex = self.getAudioStreamIndex(player); + state.PlayState.BufferedRanges = self.getBufferedRanges(player); + + state.PlayState.PlayMethod = self.playMethod(player); + + if (mediaSource) { + state.PlayState.LiveStreamId = mediaSource.LiveStreamId; + } + state.PlayState.PlaySessionId = self.playSessionId(player); + state.PlayState.PlaylistItemId = self.getCurrentPlaylistItemId(player); + } + + if (mediaSource) { + + state.PlayState.MediaSourceId = mediaSource.Id; + + state.NowPlayingItem = { + RunTimeTicks: mediaSource.RunTimeTicks + }; + + state.PlayState.CanSeek = (mediaSource.RunTimeTicks || 0) > 0 || canPlayerSeek(player); + } + + if (item) { + + state.NowPlayingItem = getNowPlayingItemForReporting(player, item, mediaSource); + } + + state.MediaSource = mediaSource; + + return state; + }; + + self.duration = function (player) { + + player = player || self._currentPlayer; + + if (player && !enableLocalPlaylistManagement(player) && !player.isLocalPlayer) { + return player.duration(); + } + + if (!player) { + throw new Error('player cannot be null'); + } + var mediaSource = self.currentMediaSource(player); - if (mediaSource && mediaSource.RunTimeTicks) return mediaSource.RunTimeTicks; + + if (mediaSource && mediaSource.RunTimeTicks) { + return mediaSource.RunTimeTicks; + } + var playerDuration = player.duration(); - return playerDuration && (playerDuration *= 1e4), playerDuration - }, self.getCurrentTicks = getCurrentTicks, self.getPlaybackInfo = function(item, options) { + + if (playerDuration) { + playerDuration *= 10000; + } + + return playerDuration; + }; + + function getCurrentTicks(player) { + + if (!player) { + throw new Error('player cannot be null'); + } + + var playerTime = Math.floor(10000 * (player || self._currentPlayer).currentTime()); + + var streamInfo = getPlayerData(player).streamInfo; + if (streamInfo) { + playerTime += getPlayerData(player).streamInfo.transcodingOffsetTicks || 0; + } + + return playerTime; + } + + // Only used internally + self.getCurrentTicks = getCurrentTicks; + + function playPhotos(items, options, user) { + + var playStartIndex = options.startIndex || 0; + var player = getPlayer(items[playStartIndex], options); + + loading.hide(); + + options.items = items; + + return player.play(options); + } + + function playWithIntros(items, options, user) { + + var playStartIndex = options.startIndex || 0; + var firstItem = items[playStartIndex]; + + // If index was bad, reset it + if (!firstItem) { + playStartIndex = 0; + firstItem = items[playStartIndex]; + } + + // If it's still null then there's nothing to play + if (!firstItem) { + showPlaybackInfoErrorMessage(self, 'NoCompatibleStream', false); + return Promise.reject(); + } + + if (firstItem.MediaType === "Photo") { + + return playPhotos(items, options, user); + } + + var apiClient = connectionManager.getApiClient(firstItem.ServerId); + + return getIntros(firstItem, apiClient, options).then(function (introsResult) { + + var introItems = introsResult.Items; + var introPlayOptions; + + firstItem.playOptions = truncatePlayOptions(options); + + if (introItems.length) { + + introPlayOptions = { + fullscreen: firstItem.playOptions.fullscreen + }; + + } else { + introPlayOptions = firstItem.playOptions; + } + + items = introItems.concat(items); + + // Needed by players that manage their own playlist + introPlayOptions.items = items; + introPlayOptions.startIndex = playStartIndex; + + return playInternal(items[playStartIndex], introPlayOptions, function () { + + self._playQueueManager.setPlaylist(items); + + setPlaylistState(items[playStartIndex].PlaylistItemId, playStartIndex); + loading.hide(); + }); + }); + } + + // Set playlist state. Using a method allows for overloading in derived player implementations + function setPlaylistState(playlistItemId, index) { + + if (!isNaN(index)) { + self._playQueueManager.setPlaylistState(playlistItemId, index); + } + } + + function playInternal(item, playOptions, onPlaybackStartedFn) { + + if (item.IsPlaceHolder) { + loading.hide(); + showPlaybackInfoErrorMessage(self, 'PlaceHolder', true); + return Promise.reject(); + } + + // Normalize defaults to simplfy checks throughout the process + normalizePlayOptions(playOptions); + + if (playOptions.isFirstItem) { + playOptions.isFirstItem = false; + } else { + playOptions.isFirstItem = true; + } + + return runInterceptors(item, playOptions).then(function () { + + if (playOptions.fullscreen) { + loading.show(); + } + + // TODO: This should be the media type requested, not the original media type + var mediaType = item.MediaType; + + var onBitrateDetectionFailure = function () { + return playAfterBitrateDetect(getSavedMaxStreamingBitrate(connectionManager.getApiClient(item.ServerId), mediaType), item, playOptions, onPlaybackStartedFn); + }; + + if (!isServerItem(item) || itemHelper.isLocalItem(item)) { + return onBitrateDetectionFailure(); + } + + var apiClient = connectionManager.getApiClient(item.ServerId); + apiClient.getEndpointInfo().then(function (endpointInfo) { + + if ((mediaType === 'Video' || mediaType === 'Audio') && appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType)) { + + return apiClient.detectBitrate().then(function (bitrate) { + + appSettings.maxStreamingBitrate(endpointInfo.IsInNetwork, mediaType, bitrate); + + return playAfterBitrateDetect(bitrate, item, playOptions, onPlaybackStartedFn); + + }, onBitrateDetectionFailure); + + } else { + + onBitrateDetectionFailure(); + } + + }, onBitrateDetectionFailure); + + }, onInterceptorRejection); + } + + function onInterceptorRejection() { + var player = self._currentPlayer; + + if (player) { + destroyPlayer(player); + removeCurrentPlayer(player); + } + + events.trigger(self, 'playbackcancelled'); + + return Promise.reject(); + } + + function destroyPlayer(player) { + player.destroy(); + } + + function runInterceptors(item, playOptions) { + + return new Promise(function (resolve, reject) { + + var interceptors = pluginManager.ofType('preplayintercept'); + + interceptors.sort(function (a, b) { + return (a.order || 0) - (b.order || 0); + }); + + if (!interceptors.length) { + resolve(); + return; + } + + loading.hide(); + + var options = Object.assign({}, playOptions); + + options.mediaType = item.MediaType; + options.item = item; + + runNextPrePlay(interceptors, 0, options, resolve, reject); + }); + } + + function runNextPrePlay(interceptors, index, options, resolve, reject) { + + if (index >= interceptors.length) { + resolve(); + return; + } + + var interceptor = interceptors[index]; + + interceptor.intercept(options).then(function () { + + runNextPrePlay(interceptors, index + 1, options, resolve, reject); + + }, reject); + } + + function sendPlaybackListToPlayer(player, items, deviceProfile, maxBitrate, apiClient, startPositionTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, startIndex) { + + return setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositionTicks).then(function () { + + loading.hide(); + + return player.play({ + items: items, + startPositionTicks: startPositionTicks || 0, + mediaSourceId: mediaSourceId, + audioStreamIndex: audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex, + startIndex: startIndex + }); + }); + } + + function playAfterBitrateDetect(maxBitrate, item, playOptions, onPlaybackStartedFn) { + + var startPosition = playOptions.startPositionTicks; + + var player = getPlayer(item, playOptions); + var activePlayer = self._currentPlayer; + + var promise; + + if (activePlayer) { + + // TODO: if changing players within the same playlist, this will cause nextItem to be null + self._playNextAfterEnded = false; + promise = onPlaybackChanging(activePlayer, player, item); + } else { + promise = Promise.resolve(); + } + + if (!isServerItem(item) || item.MediaType === 'Game' || item.MediaType === 'Book') { + return promise.then(function () { + var streamInfo = createStreamInfoFromUrlItem(item); + streamInfo.fullscreen = playOptions.fullscreen; + getPlayerData(player).isChangingStream = false; + return player.play(streamInfo).then(function () { + loading.hide(); + onPlaybackStartedFn(); + onPlaybackStarted(player, playOptions, streamInfo); + }, function () { + // TODO: show error message + self.stop(player); + }); + }); + } + + return Promise.all([promise, player.getDeviceProfile(item)]).then(function (responses) { + + var deviceProfile = responses[1]; + + var apiClient = connectionManager.getApiClient(item.ServerId); + + var mediaSourceId = playOptions.mediaSourceId; + var audioStreamIndex = playOptions.audioStreamIndex; + var subtitleStreamIndex = playOptions.subtitleStreamIndex; + + if (player && !enableLocalPlaylistManagement(player)) { + + return sendPlaybackListToPlayer(player, playOptions.items, deviceProfile, maxBitrate, apiClient, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex, playOptions.startIndex); + } + + // this reference was only needed by sendPlaybackListToPlayer + playOptions.items = null; + + return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex).then(function (mediaSource) { + + var streamInfo = createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition); + + streamInfo.fullscreen = playOptions.fullscreen; + + getPlayerData(player).isChangingStream = false; + getPlayerData(player).maxStreamingBitrate = maxBitrate; + + return player.play(streamInfo).then(function () { + loading.hide(); + onPlaybackStartedFn(); + onPlaybackStarted(player, playOptions, streamInfo, mediaSource); + }, function (err) { + + // TODO: Improve this because it will report playback start on a failure + onPlaybackStartedFn(); + onPlaybackStarted(player, playOptions, streamInfo, mediaSource); + setTimeout(function () { + onPlaybackError.call(player, err, { + type: 'mediadecodeerror', + streamInfo: streamInfo + }); + }, 100); + }); + }); + }); + } + + self.getPlaybackInfo = function (item, options) { + options = options || {}; - var startPosition = options.startPositionTicks || 0, - mediaType = options.mediaType || item.MediaType, - player = getPlayer(item, options), - apiClient = connectionManager.getApiClient(item.ServerId); - return apiClient.getEndpointInfo().then(function() { + var startPosition = options.startPositionTicks || 0; + var mediaType = options.mediaType || item.MediaType; + var player = getPlayer(item, options); + var apiClient = connectionManager.getApiClient(item.ServerId); + + // Call this just to ensure the value is recorded, it is needed with getSavedMaxStreamingBitrate + return apiClient.getEndpointInfo().then(function () { + var maxBitrate = getSavedMaxStreamingBitrate(connectionManager.getApiClient(item.ServerId), mediaType); - return player.getDeviceProfile(item).then(function(deviceProfile) { - return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, options.mediaSourceId, options.audioStreamIndex, options.subtitleStreamIndex).then(function(mediaSource) { - return createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition) - }) - }) - }) - }, self.getPlaybackMediaSources = function(item, options) { + + return player.getDeviceProfile(item).then(function (deviceProfile) { + + return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, options.mediaSourceId, options.audioStreamIndex, options.subtitleStreamIndex).then(function (mediaSource) { + + return createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition); + }); + }); + }); + }; + + self.getPlaybackMediaSources = function (item, options) { + options = options || {}; - var startPosition = options.startPositionTicks || 0, - mediaType = options.mediaType || item.MediaType, - player = getPlayer(item, options, !0), - apiClient = connectionManager.getApiClient(item.ServerId); - return apiClient.getEndpointInfo().then(function() { + var startPosition = options.startPositionTicks || 0; + var mediaType = options.mediaType || item.MediaType; + // TODO: Remove the true forceLocalPlayer hack + var player = getPlayer(item, options, true); + var apiClient = connectionManager.getApiClient(item.ServerId); + + // Call this just to ensure the value is recorded, it is needed with getSavedMaxStreamingBitrate + return apiClient.getEndpointInfo().then(function () { + var maxBitrate = getSavedMaxStreamingBitrate(connectionManager.getApiClient(item.ServerId), mediaType); - return player.getDeviceProfile(item).then(function(deviceProfile) { - return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, !1, null, null, null, null).then(function(playbackInfoResult) { - return playbackInfoResult.MediaSources - }) - }) - }) - }, self.setCurrentPlaylistItem = function(playlistItemId, player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.setCurrentPlaylistItem(playlistItemId); - for (var newItem, newItemIndex, playlist = self._playQueueManager.getPlaylist(), i = 0, length = playlist.length; i < length; i++) + + return player.getDeviceProfile(item).then(function (deviceProfile) { + + return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, false, null, null, null, null).then(function (playbackInfoResult) { + + return playbackInfoResult.MediaSources; + }); + }); + }); + + }; + + function createStreamInfo(apiClient, type, item, mediaSource, startPosition) { + + var mediaUrl; + var contentType; + var transcodingOffsetTicks = 0; + var playerStartPositionTicks = startPosition; + var liveStreamId = mediaSource.LiveStreamId; + + var playMethod = 'Transcode'; + + var mediaSourceContainer = (mediaSource.Container || '').toLowerCase(); + var directOptions; + + if (type === 'Video' || type === 'Audio') { + + contentType = getMimeType(type.toLowerCase(), mediaSourceContainer); + + if (mediaSource.enableDirectPlay) { + mediaUrl = mediaSource.Path; + + playMethod = 'DirectPlay'; + + } + + else if (mediaSource.StreamUrl) { + + // Only used for audio + playMethod = 'Transcode'; + mediaUrl = mediaSource.StreamUrl; + } + + else if (mediaSource.SupportsDirectStream) { + + directOptions = { + Static: true, + mediaSourceId: mediaSource.Id, + deviceId: apiClient.deviceId(), + api_key: apiClient.accessToken() + }; + + if (mediaSource.ETag) { + directOptions.Tag = mediaSource.ETag; + } + + if (mediaSource.LiveStreamId) { + directOptions.LiveStreamId = mediaSource.LiveStreamId; + } + + var prefix = type === 'Video' ? 'Videos' : 'Audio'; + mediaUrl = apiClient.getUrl(prefix + '/' + item.Id + '/stream.' + mediaSourceContainer, directOptions); + + playMethod = 'DirectStream'; + + } else if (mediaSource.SupportsTranscoding) { + + mediaUrl = apiClient.getUrl(mediaSource.TranscodingUrl); + + if (mediaSource.TranscodingSubProtocol === 'hls') { + + contentType = 'application/x-mpegURL'; + + } else { + + playerStartPositionTicks = null; + contentType = getMimeType(type.toLowerCase(), mediaSource.TranscodingContainer); + + if (mediaUrl.toLowerCase().indexOf('copytimestamps=true') === -1) { + transcodingOffsetTicks = startPosition || 0; + } + } + } + + } else { + + // All other media types + mediaUrl = mediaSource.Path; + playMethod = 'DirectPlay'; + } + + // Fallback (used for offline items) + if (!mediaUrl && mediaSource.SupportsDirectPlay) { + mediaUrl = mediaSource.Path; + playMethod = 'DirectPlay'; + } + + var resultInfo = { + url: mediaUrl, + mimeType: contentType, + transcodingOffsetTicks: transcodingOffsetTicks, + playMethod: playMethod, + playerStartPositionTicks: playerStartPositionTicks, + item: item, + mediaSource: mediaSource, + textTracks: getTextTracks(apiClient, item, mediaSource), + // TODO: Deprecate + tracks: getTextTracks(apiClient, item, mediaSource), + mediaType: type, + liveStreamId: liveStreamId, + playSessionId: getParam('playSessionId', mediaUrl), + title: item.Name + }; + + var backdropUrl = backdropImageUrl(apiClient, item, {}); + if (backdropUrl) { + resultInfo.backdropUrl = backdropUrl; + } + + return resultInfo; + } + + function getTextTracks(apiClient, item, mediaSource) { + + var subtitleStreams = mediaSource.MediaStreams.filter(function (s) { + return s.Type === 'Subtitle'; + }); + + var textStreams = subtitleStreams.filter(function (s) { + return s.DeliveryMethod === 'External'; + }); + + var tracks = []; + + for (var i = 0, length = textStreams.length; i < length; i++) { + + var textStream = textStreams[i]; + var textStreamUrl; + + if (itemHelper.isLocalItem(item)) { + textStreamUrl = textStream.Path; + } else { + textStreamUrl = !textStream.IsExternalUrl ? apiClient.getUrl(textStream.DeliveryUrl) : textStream.DeliveryUrl; + } + + tracks.push({ + url: textStreamUrl, + language: (textStream.Language || 'und'), + isDefault: textStream.Index === mediaSource.DefaultSubtitleStreamIndex, + index: textStream.Index, + format: textStream.Codec + }); + } + + return tracks; + } + + function getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex) { + + return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, true, mediaSourceId, audioStreamIndex, subtitleStreamIndex, null).then(function (playbackInfoResult) { + + if (validatePlaybackInfoResult(self, playbackInfoResult)) { + + return getOptimalMediaSource(apiClient, item, playbackInfoResult.MediaSources).then(function (mediaSource) { + if (mediaSource) { + + if (mediaSource.RequiresOpening && !mediaSource.LiveStreamId) { + + return getLiveStream(player, apiClient, item, playbackInfoResult.PlaySessionId, deviceProfile, maxBitrate, startPosition, mediaSource, null, null).then(function (openLiveStreamResult) { + + return supportsDirectPlay(apiClient, item, openLiveStreamResult.MediaSource).then(function (result) { + + openLiveStreamResult.MediaSource.enableDirectPlay = result; + return openLiveStreamResult.MediaSource; + }); + + }); + + } else { + return mediaSource; + } + } else { + showPlaybackInfoErrorMessage(self, 'NoCompatibleStream'); + return Promise.reject(); + } + }); + } else { + return Promise.reject(); + } + }); + } + + function getPlayer(item, playOptions, forceLocalPlayers) { + + var serverItem = isServerItem(item); + return getAutomaticPlayers(self, forceLocalPlayers).filter(function (p) { + + if (p.canPlayMediaType(item.MediaType)) { + + if (serverItem) { + if (p.canPlayItem) { + return p.canPlayItem(item, playOptions); + } + return true; + } + + else if (item.Url && p.canPlayUrl) { + return p.canPlayUrl(item.Url); + } + } + + return false; + + })[0]; + } + + self.setCurrentPlaylistItem = function (playlistItemId, player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.setCurrentPlaylistItem(playlistItemId); + } + + var newItem; + var newItemIndex; + var playlist = self._playQueueManager.getPlaylist(); + + for (var i = 0, length = playlist.length; i < length; i++) { if (playlist[i].PlaylistItemId === playlistItemId) { - newItem = playlist[i], newItemIndex = i; - break - } if (newItem) { + newItem = playlist[i]; + newItemIndex = i; + break; + } + } + + if (newItem) { + var newItemPlayOptions = newItem.playOptions || {}; - playInternal(newItem, newItemPlayOptions, function() { - setPlaylistState(newItem.PlaylistItemId, newItemIndex) - }) + + playInternal(newItem, newItemPlayOptions, function () { + setPlaylistState(newItem.PlaylistItemId, newItemIndex); + }); } - }, self.removeFromPlaylist = function(playlistItemIds, player) { - if (!playlistItemIds) throw new Error("Invalid playlistItemIds"); - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.removeFromPlaylist(playlistItemIds); + }; + + self.removeFromPlaylist = function (playlistItemIds, player) { + + if (!playlistItemIds) { + throw new Error('Invalid playlistItemIds'); + } + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.removeFromPlaylist(playlistItemIds); + } + var removeResult = self._playQueueManager.removeFromPlaylist(playlistItemIds); - if ("empty" === removeResult.result) return self.stop(player); - var isCurrentIndex = removeResult.isCurrentIndex; - return events.trigger(player, "playlistitemremove", [{ - playlistItemIds: playlistItemIds - }]), isCurrentIndex ? self.setCurrentPlaylistItem(self._playQueueManager.getPlaylist()[0].PlaylistItemId, player) : Promise.resolve() - }, self.movePlaylistItem = function(playlistItemId, newIndex, player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.movePlaylistItem(playlistItemId, newIndex); - var moveResult = self._playQueueManager.movePlaylistItem(playlistItemId, newIndex); - "noop" !== moveResult.result && events.trigger(player, "playlistitemmove", [{ - playlistItemId: moveResult.playlistItemId, - newIndex: moveResult.newIndex - }]) - }, self.getCurrentPlaylistIndex = function(player) { - return player = player || self._currentPlayer, player && !enableLocalPlaylistManagement(player) ? player.getCurrentPlaylistIndex() : self._playQueueManager.getCurrentPlaylistIndex() - }, self.getCurrentPlaylistItemId = function(player) { - return player = player || self._currentPlayer, player && !enableLocalPlaylistManagement(player) ? player.getCurrentPlaylistItemId() : self._playQueueManager.getCurrentPlaylistItemId() - }, self.channelUp = function(player) { - return player = player || self._currentPlayer, self.nextTrack(player) - }, self.channelDown = function(player) { - return player = player || self._currentPlayer, self.previousTrack(player) - }, self.nextTrack = function(player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.nextTrack(); - var newItemInfo = self._playQueueManager.getNextItemInfo(); - if (newItemInfo) { - console.log("playing next track"); - var newItemPlayOptions = newItemInfo.item.playOptions || {}; - playInternal(newItemInfo.item, newItemPlayOptions, function() { - setPlaylistState(newItemInfo.item.PlaylistItemId, newItemInfo.index) - }) + + if (removeResult.result === 'empty') { + return self.stop(player); } - }, self.previousTrack = function(player) { - if ((player = player || self._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.previousTrack(); + + var isCurrentIndex = removeResult.isCurrentIndex; + + events.trigger(player, 'playlistitemremove', [ + { + playlistItemIds: playlistItemIds + }]); + + if (isCurrentIndex) { + + return self.setCurrentPlaylistItem(self._playQueueManager.getPlaylist()[0].PlaylistItemId, player); + } + + return Promise.resolve(); + }; + + self.movePlaylistItem = function (playlistItemId, newIndex, player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.movePlaylistItem(playlistItemId, newIndex); + } + + var moveResult = self._playQueueManager.movePlaylistItem(playlistItemId, newIndex); + + if (moveResult.result === 'noop') { + return; + } + + events.trigger(player, 'playlistitemmove', [ + { + playlistItemId: moveResult.playlistItemId, + newIndex: moveResult.newIndex + }]); + }; + + self.getCurrentPlaylistIndex = function (player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.getCurrentPlaylistIndex(); + } + + return self._playQueueManager.getCurrentPlaylistIndex(); + }; + + self.getCurrentPlaylistItemId = function (player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.getCurrentPlaylistItemId(); + } + + return self._playQueueManager.getCurrentPlaylistItemId(); + }; + + self.channelUp = function (player) { + + player = player || self._currentPlayer; + return self.nextTrack(player); + }; + + self.channelDown = function (player) { + + player = player || self._currentPlayer; + return self.previousTrack(player); + }; + + self.nextTrack = function (player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.nextTrack(); + } + + var newItemInfo = self._playQueueManager.getNextItemInfo(); + + if (newItemInfo) { + + console.log('playing next track'); + + var newItemPlayOptions = newItemInfo.item.playOptions || {}; + + playInternal(newItemInfo.item, newItemPlayOptions, function () { + setPlaylistState(newItemInfo.item.PlaylistItemId, newItemInfo.index); + }); + } + }; + + self.previousTrack = function (player) { + + player = player || self._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.previousTrack(); + } + var newIndex = self.getCurrentPlaylistIndex(player) - 1; if (newIndex >= 0) { - var playlist = self._playQueueManager.getPlaylist(), - newItem = playlist[newIndex]; + + var playlist = self._playQueueManager.getPlaylist(); + var newItem = playlist[newIndex]; + if (newItem) { + var newItemPlayOptions = newItem.playOptions || {}; - newItemPlayOptions.startPositionTicks = 0, playInternal(newItem, newItemPlayOptions, function() { - setPlaylistState(newItem.PlaylistItemId, newIndex) - }) + newItemPlayOptions.startPositionTicks = 0; + + playInternal(newItem, newItemPlayOptions, function () { + setPlaylistState(newItem.PlaylistItemId, newIndex); + }); } } - }, self.queue = function(options, player) { - queue(options, "", player) - }, self.queueNext = function(options, player) { - queue(options, "next", player) - }, events.on(pluginManager, "registered", function(e, plugin) { - "mediaplayer" === plugin.type && initMediaPlayer(plugin) - }), pluginManager.ofType("mediaplayer").map(initMediaPlayer), self.onAppClose = function() { - var player = this._currentPlayer; - player && this.isPlaying(player) && (this._playNextAfterEnded = !1, onPlaybackStopped.call(player)) - }, self.playbackStartTime = function(player) { - if ((player = player || this._currentPlayer) && !enableLocalPlaylistManagement(player) && !player.isLocalPlayer) return player.playbackStartTime(); - var streamInfo = getPlayerData(player).streamInfo; - return streamInfo ? streamInfo.playbackStartTimeTicks : null - }, apphost.supports("remotecontrol") && require(["serverNotifications"], function(serverNotifications) { - events.on(serverNotifications, "ServerShuttingDown", self.setDefaultPlayerActive.bind(self)), events.on(serverNotifications, "ServerRestarting", self.setDefaultPlayerActive.bind(self)) - }) - } - var startingPlaySession = (new Date).getTime(); - return PlaybackManager.prototype.getCurrentPlayer = function() { - return this._currentPlayer - }, PlaybackManager.prototype.currentTime = function(player) { - return player = player || this._currentPlayer, !player || enableLocalPlaylistManagement(player) || player.isLocalPlayer ? this.getCurrentTicks(player) : player.currentTime() - }, PlaybackManager.prototype.nextItem = function(player) { - if ((player = player || this._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.nextItem(); - var nextItem = this._playQueueManager.getNextItemInfo(); - if (!nextItem || !nextItem.item) return Promise.reject(); - var apiClient = connectionManager.getApiClient(nextItem.item.ServerId); - return apiClient.getItem(apiClient.getCurrentUserId(), nextItem.item.Id) - }, PlaybackManager.prototype.canQueue = function(item) { - return "MusicAlbum" === item.Type || "MusicArtist" === item.Type || "MusicGenre" === item.Type ? this.canQueueMediaType("Audio") : this.canQueueMediaType(item.MediaType) - }, PlaybackManager.prototype.canQueueMediaType = function(mediaType) { - return !!this._currentPlayer && this._currentPlayer.canPlayMediaType(mediaType) - }, PlaybackManager.prototype.isMuted = function(player) { - return !!(player = player || this._currentPlayer) && player.isMuted() - }, PlaybackManager.prototype.setMute = function(mute, player) { - (player = player || this._currentPlayer) && player.setMute(mute) - }, PlaybackManager.prototype.toggleMute = function(mute, player) { - (player = player || this._currentPlayer) && (player.toggleMute ? player.toggleMute() : player.setMute(!player.isMuted())) - }, PlaybackManager.prototype.toggleDisplayMirroring = function() { - this.enableDisplayMirroring(!this.enableDisplayMirroring()) - }, PlaybackManager.prototype.enableDisplayMirroring = function(enabled) { - if (null != enabled) { - var val = enabled ? "1" : "0"; - return void appSettings.set("displaymirror", val) - } - return "0" !== (appSettings.get("displaymirror") || "") - }, PlaybackManager.prototype.nextChapter = function(player) { - player = player || this._currentPlayer; - var item = this.currentItem(player), - ticks = this.getCurrentTicks(player), - nextChapter = (item.Chapters || []).filter(function(i) { - return i.StartPositionTicks > ticks - })[0]; - nextChapter ? this.seek(nextChapter.StartPositionTicks, player) : this.nextTrack(player) - }, PlaybackManager.prototype.previousChapter = function(player) { - player = player || this._currentPlayer; - var item = this.currentItem(player), - ticks = this.getCurrentTicks(player); - ticks -= 1e8, 0 === this.getCurrentPlaylistIndex(player) && (ticks = Math.max(ticks, 0)); - var previousChapters = (item.Chapters || []).filter(function(i) { - return i.StartPositionTicks <= ticks - }); - previousChapters.length ? this.seek(previousChapters[previousChapters.length - 1].StartPositionTicks, player) : this.previousTrack(player) - }, PlaybackManager.prototype.fastForward = function(player) { - if (player = player || this._currentPlayer, null != player.fastForward) return void player.fastForward(userSettings.skipForwardLength()); - var offsetTicks = 1e4 * userSettings.skipForwardLength(); - this.seekRelative(offsetTicks, player) - }, PlaybackManager.prototype.rewind = function(player) { - if (player = player || this._currentPlayer, null != player.rewind) return void player.rewind(userSettings.skipBackLength()); - var offsetTicks = 0 - 1e4 * userSettings.skipBackLength(); - this.seekRelative(offsetTicks, player) - }, PlaybackManager.prototype.seekPercent = function(percent, player) { - player = player || this._currentPlayer; - var ticks = this.duration(player) || 0; - percent /= 100, ticks *= percent, this.seek(parseInt(ticks), player) - }, PlaybackManager.prototype.playTrailers = function(item) { - var player = this._currentPlayer; - if (player && player.playTrailers) return player.playTrailers(item); - var apiClient = connectionManager.getApiClient(item.ServerId), - instance = this; - if (item.LocalTrailerCount) return apiClient.getLocalTrailers(apiClient.getCurrentUserId(), item.Id).then(function(result) { - return instance.play({ - items: result - }) - }); - var remoteTrailers = item.RemoteTrailers || []; - return remoteTrailers.length ? this.play({ - items: remoteTrailers.map(function(t) { - return { - Name: t.Name || item.Name + " Trailer", - Url: t.Url, - MediaType: "Video", - Type: "Trailer", - ServerId: apiClient.serverId() + }; + + self.queue = function (options, player) { + queue(options, '', player); + }; + + self.queueNext = function (options, player) { + queue(options, 'next', player); + }; + + function queue(options, mode, player) { + + player = player || self._currentPlayer; + + if (!player) { + return self.play(options); + } + + if (options.items) { + + return translateItemsForPlayback(options.items, options).then(function (items) { + + // TODO: Handle options.startIndex for photos + queueAll(items, mode, player); + + }); + + } else { + + if (!options.serverId) { + throw new Error('serverId required!'); } - }) - }) : Promise.reject() - }, PlaybackManager.prototype.getSubtitleUrl = function(textStream, serverId) { - var apiClient = connectionManager.getApiClient(serverId); - return textStream.IsExternalUrl ? textStream.DeliveryUrl : apiClient.getUrl(textStream.DeliveryUrl) - }, PlaybackManager.prototype.stop = function(player) { - return player = player || this._currentPlayer, player ? (enableLocalPlaylistManagement(player) && (this._playNextAfterEnded = !1), player.stop(!0, !0)) : Promise.resolve() - }, PlaybackManager.prototype.getBufferedRanges = function(player) { - return player = player || this._currentPlayer, player && player.getBufferedRanges ? player.getBufferedRanges() : [] - }, PlaybackManager.prototype.playPause = function(player) { - if (player = player || this._currentPlayer) return player.playPause ? player.playPause() : player.paused() ? this.unpause(player) : this.pause(player) - }, PlaybackManager.prototype.paused = function(player) { - if (player = player || this._currentPlayer) return player.paused() - }, PlaybackManager.prototype.pause = function(player) { - (player = player || this._currentPlayer) && player.pause() - }, PlaybackManager.prototype.unpause = function(player) { - (player = player || this._currentPlayer) && player.unpause() - }, PlaybackManager.prototype.instantMix = function(item, player) { - if ((player = player || this._currentPlayer) && player.instantMix) return player.instantMix(item); - var apiClient = connectionManager.getApiClient(item.ServerId), - options = {}; - options.UserId = apiClient.getCurrentUserId(), options.Limit = 200; + + return getItemsForPlayback(options.serverId, { + + Ids: options.ids.join(',') + + }).then(function (result) { + + return translateItemsForPlayback(result.Items, options).then(function (items) { + + // TODO: Handle options.startIndex for photos + queueAll(items, mode, player); + + }); + }); + } + } + + function queueAll(items, mode, player) { + + if (!items.length) { + return; + } + + if (!player.isLocalPlayer) { + if (mode === 'next') { + player.queueNext({ + items: items + }); + } else { + player.queue({ + items: items + }); + } + return; + } + + var queueDirectToPlayer = player && !enableLocalPlaylistManagement(player); + + if (queueDirectToPlayer) { + + var apiClient = connectionManager.getApiClient(items[0].ServerId); + + player.getDeviceProfile(items[0]).then(function (profile) { + + setStreamUrls(items, profile, self.getMaxStreamingBitrate(player), apiClient, 0).then(function () { + + if (mode === 'next') { + player.queueNext(items); + } else { + player.queue(items); + } + }); + }); + + return; + } + + if (mode === 'next') { + self._playQueueManager.queueNext(items); + } else { + self._playQueueManager.queue(items); + } + } + + function onPlayerProgressInterval() { + var player = this; + sendProgressUpdate(player, 'timeupdate'); + } + + function startPlaybackProgressTimer(player) { + + stopPlaybackProgressTimer(player); + + player._progressInterval = setInterval(onPlayerProgressInterval.bind(player), 10000); + } + + function stopPlaybackProgressTimer(player) { + + if (player._progressInterval) { + + clearInterval(player._progressInterval); + player._progressInterval = null; + } + } + + function onPlaybackStarted(player, playOptions, streamInfo, mediaSource) { + + if (!player) { + throw new Error('player cannot be null'); + } + + setCurrentPlayerInternal(player); + + var playerData = getPlayerData(player); + + playerData.streamInfo = streamInfo; + + streamInfo.playbackStartTimeTicks = new Date().getTime() * 10000; + + if (mediaSource) { + playerData.audioStreamIndex = mediaSource.DefaultAudioStreamIndex; + playerData.subtitleStreamIndex = mediaSource.DefaultSubtitleStreamIndex; + } else { + playerData.audioStreamIndex = null; + playerData.subtitleStreamIndex = null; + } + + self._playNextAfterEnded = true; + var isFirstItem = playOptions.isFirstItem; + var fullscreen = playOptions.fullscreen; + + var state = self.getPlayerState(player, streamInfo.item, streamInfo.mediaSource); + + reportPlayback(self, state, player, true, state.NowPlayingItem.ServerId, 'reportPlaybackStart'); + + state.IsFirstItem = isFirstItem; + state.IsFullscreen = fullscreen; + events.trigger(player, 'playbackstart', [state]); + events.trigger(self, 'playbackstart', [player, state]); + + // only used internally as a safeguard to avoid reporting other events to the server before playback start + streamInfo.started = true; + + startPlaybackProgressTimer(player); + } + + function onPlaybackStartedFromSelfManagingPlayer(e, item, mediaSource) { + + var player = this; + setCurrentPlayerInternal(player); + + var playOptions = item.playOptions || {}; + var isFirstItem = playOptions.isFirstItem; + var fullscreen = playOptions.fullscreen; + + playOptions.isFirstItem = false; + + var playerData = getPlayerData(player); + playerData.streamInfo = {}; + + var streamInfo = playerData.streamInfo; + streamInfo.playbackStartTimeTicks = new Date().getTime() * 10000; + + var state = self.getPlayerState(player, item, mediaSource); + + reportPlayback(self, state, player, true, state.NowPlayingItem.ServerId, 'reportPlaybackStart'); + + state.IsFirstItem = isFirstItem; + state.IsFullscreen = fullscreen; + events.trigger(player, 'playbackstart', [state]); + events.trigger(self, 'playbackstart', [player, state]); + + // only used internally as a safeguard to avoid reporting other events to the server before playback start + streamInfo.started = true; + + startPlaybackProgressTimer(player); + } + + function onPlaybackStoppedFromSelfManagingPlayer(e, playerStopInfo) { + + var player = this; + + stopPlaybackProgressTimer(player); + var state = self.getPlayerState(player, playerStopInfo.item, playerStopInfo.mediaSource); + + var nextItem = playerStopInfo.nextItem; + var nextMediaType = playerStopInfo.nextMediaType; + + var playbackStopInfo = { + player: player, + state: state, + nextItem: (nextItem ? nextItem.item : null), + nextMediaType: nextMediaType + }; + + state.NextMediaType = nextMediaType; + + var streamInfo = getPlayerData(player).streamInfo; + + // only used internally as a safeguard to avoid reporting other events to the server after playback stopped + streamInfo.ended = true; + + if (isServerItem(playerStopInfo.item)) { + + state.PlayState.PositionTicks = (playerStopInfo.positionMs || 0) * 10000; + + reportPlayback(self, state, player, true, playerStopInfo.item.ServerId, 'reportPlaybackStopped'); + } + + state.NextItem = playbackStopInfo.nextItem; + + events.trigger(player, 'playbackstop', [state]); + events.trigger(self, 'playbackstop', [playbackStopInfo]); + + var nextItemPlayOptions = nextItem ? (nextItem.item.playOptions || getDefaultPlayOptions()) : getDefaultPlayOptions(); + var newPlayer = nextItem ? getPlayer(nextItem.item, nextItemPlayOptions) : null; + + if (newPlayer !== player) { + destroyPlayer(player); + removeCurrentPlayer(player); + } + } + + function enablePlaybackRetryWithTranscoding(streamInfo, errorType, currentlyPreventsVideoStreamCopy, currentlyPreventsAudioStreamCopy) { + + // mediadecodeerror, medianotsupported, network, servererror + + if (streamInfo.mediaSource.SupportsTranscoding && (!currentlyPreventsVideoStreamCopy || !currentlyPreventsAudioStreamCopy)) { + + return true; + } + + return false; + } + + function onPlaybackError(e, error) { + + var player = this; + error = error || {}; + + // network + // mediadecodeerror + // medianotsupported + var errorType = error.type; + + console.log('playbackmanager playback error type: ' + (errorType || '')); + + var streamInfo = error.streamInfo || getPlayerData(player).streamInfo; + + if (streamInfo) { + + var currentlyPreventsVideoStreamCopy = streamInfo.url.toLowerCase().indexOf('allowvideostreamcopy=false') !== -1; + var currentlyPreventsAudioStreamCopy = streamInfo.url.toLowerCase().indexOf('allowaudiostreamcopy=false') !== -1; + + // Auto switch to transcoding + if (enablePlaybackRetryWithTranscoding(streamInfo, errorType, currentlyPreventsVideoStreamCopy, currentlyPreventsAudioStreamCopy)) { + + var startTime = getCurrentTicks(player) || streamInfo.playerStartPositionTicks; + + changeStream(player, startTime, { + + // force transcoding + EnableDirectPlay: false, + EnableDirectStream: false, + AllowVideoStreamCopy: false, + AllowAudioStreamCopy: currentlyPreventsAudioStreamCopy || currentlyPreventsVideoStreamCopy ? false : null + + }, true); + + return; + } + } + + var displayErrorCode = 'NoCompatibleStream'; + onPlaybackStopped.call(player, e, displayErrorCode); + } + + function onPlaybackStopped(e, displayErrorCode) { + + var player = this; + + if (getPlayerData(player).isChangingStream) { + return; + } + + stopPlaybackProgressTimer(player); + + // User clicked stop or content ended + var state = self.getPlayerState(player); + var streamInfo = getPlayerData(player).streamInfo; + + var nextItem = self._playNextAfterEnded ? self._playQueueManager.getNextItemInfo() : null; + + var nextMediaType = (nextItem ? nextItem.item.MediaType : null); + + var playbackStopInfo = { + player: player, + state: state, + nextItem: (nextItem ? nextItem.item : null), + nextMediaType: nextMediaType + }; + + state.NextMediaType = nextMediaType; + + if (isServerItem(streamInfo.item)) { + + if (player.supportsProgress === false && state.PlayState && !state.PlayState.PositionTicks) { + state.PlayState.PositionTicks = streamInfo.item.RunTimeTicks; + } + + // only used internally as a safeguard to avoid reporting other events to the server after playback stopped + streamInfo.ended = true; + + reportPlayback(self, state, player, true, streamInfo.item.ServerId, 'reportPlaybackStopped'); + } + + state.NextItem = playbackStopInfo.nextItem; + + if (!nextItem) { + self._playQueueManager.reset(); + } + + events.trigger(player, 'playbackstop', [state]); + events.trigger(self, 'playbackstop', [playbackStopInfo]); + + var nextItemPlayOptions = nextItem ? (nextItem.item.playOptions || getDefaultPlayOptions()) : getDefaultPlayOptions(); + var newPlayer = nextItem ? getPlayer(nextItem.item, nextItemPlayOptions) : null; + + if (newPlayer !== player) { + destroyPlayer(player); + removeCurrentPlayer(player); + } + + if (displayErrorCode && typeof (displayErrorCode) === 'string') { + showPlaybackInfoErrorMessage(self, displayErrorCode, nextItem); + } + else if (nextItem) { + self.nextTrack(); + } + } + + function onPlaybackChanging(activePlayer, newPlayer, newItem) { + + var state = self.getPlayerState(activePlayer); + + var serverId = self.currentItem(activePlayer).ServerId; + + // User started playing something new while existing content is playing + var promise; + + stopPlaybackProgressTimer(activePlayer); + unbindStopped(activePlayer); + + if (activePlayer === newPlayer) { + + // If we're staying with the same player, stop it + promise = activePlayer.stop(false); + + } else { + + // If we're switching players, tear down the current one + promise = activePlayer.stop(true); + } + + return promise.then(function () { + + bindStopped(activePlayer); + + if (enableLocalPlaylistManagement(activePlayer)) { + reportPlayback(self, state, activePlayer, true, serverId, 'reportPlaybackStopped'); + } + + events.trigger(self, 'playbackstop', [{ + player: activePlayer, + state: state, + nextItem: newItem, + nextMediaType: newItem.MediaType + }]); + }); + } + + function bindStopped(player) { + + if (enableLocalPlaylistManagement(player)) { + events.off(player, 'stopped', onPlaybackStopped); + events.on(player, 'stopped', onPlaybackStopped); + } + } + + function onPlaybackTimeUpdate(e) { + var player = this; + sendProgressUpdate(player, 'timeupdate'); + } + + function onPlaybackPause(e) { + var player = this; + sendProgressUpdate(player, 'pause'); + } + + function onPlaybackUnpause(e) { + var player = this; + sendProgressUpdate(player, 'unpause'); + } + + function onPlaybackVolumeChange(e) { + var player = this; + sendProgressUpdate(player, 'volumechange'); + } + + function onRepeatModeChange(e) { + var player = this; + sendProgressUpdate(player, 'repeatmodechange'); + } + + function onPlaylistItemMove(e) { + var player = this; + sendProgressUpdate(player, 'playlistitemmove', true); + } + + function onPlaylistItemRemove(e) { + var player = this; + sendProgressUpdate(player, 'playlistitemremove', true); + } + + function onPlaylistItemAdd(e) { + var player = this; + sendProgressUpdate(player, 'playlistitemadd', true); + } + + function unbindStopped(player) { + + events.off(player, 'stopped', onPlaybackStopped); + } + + function initLegacyVolumeMethods(player) { + player.getVolume = function () { + return player.volume(); + }; + player.setVolume = function (val) { + return player.volume(val); + }; + } + + function initMediaPlayer(player) { + + players.push(player); + players.sort(function (a, b) { + + return (a.priority || 0) - (b.priority || 0); + }); + + if (player.isLocalPlayer !== false) { + player.isLocalPlayer = true; + } + + player.currentState = {}; + + if (!player.getVolume || !player.setVolume) { + initLegacyVolumeMethods(player); + } + + if (enableLocalPlaylistManagement(player)) { + events.on(player, 'error', onPlaybackError); + events.on(player, 'timeupdate', onPlaybackTimeUpdate); + events.on(player, 'pause', onPlaybackPause); + events.on(player, 'unpause', onPlaybackUnpause); + events.on(player, 'volumechange', onPlaybackVolumeChange); + events.on(player, 'repeatmodechange', onRepeatModeChange); + events.on(player, 'playlistitemmove', onPlaylistItemMove); + events.on(player, 'playlistitemremove', onPlaylistItemRemove); + events.on(player, 'playlistitemadd', onPlaylistItemAdd); + } else if (player.isLocalPlayer) { + + events.on(player, 'itemstarted', onPlaybackStartedFromSelfManagingPlayer); + events.on(player, 'itemstopped', onPlaybackStoppedFromSelfManagingPlayer); + events.on(player, 'timeupdate', onPlaybackTimeUpdate); + events.on(player, 'pause', onPlaybackPause); + events.on(player, 'unpause', onPlaybackUnpause); + events.on(player, 'volumechange', onPlaybackVolumeChange); + events.on(player, 'repeatmodechange', onRepeatModeChange); + events.on(player, 'playlistitemmove', onPlaylistItemMove); + events.on(player, 'playlistitemremove', onPlaylistItemRemove); + events.on(player, 'playlistitemadd', onPlaylistItemAdd); + } + + if (player.isLocalPlayer) { + bindToFullscreenChange(player); + } + bindStopped(player); + } + + events.on(pluginManager, 'registered', function (e, plugin) { + + if (plugin.type === 'mediaplayer') { + + initMediaPlayer(plugin); + } + }); + + pluginManager.ofType('mediaplayer').map(initMediaPlayer); + + function sendProgressUpdate(player, progressEventName, reportPlaylist) { + + if (!player) { + throw new Error('player cannot be null'); + } + + var state = self.getPlayerState(player); + + if (state.NowPlayingItem) { + var serverId = state.NowPlayingItem.ServerId; + + var streamInfo = getPlayerData(player).streamInfo; + + if (streamInfo && streamInfo.started && !streamInfo.ended) { + reportPlayback(self, state, player, reportPlaylist, serverId, 'reportPlaybackProgress', progressEventName); + } + + if (streamInfo && streamInfo.liveStreamId) { + + if (new Date().getTime() - (streamInfo.lastMediaInfoQuery || 0) >= 600000) { + getLiveStreamMediaInfo(player, streamInfo, self.currentMediaSource(player), streamInfo.liveStreamId, serverId); + } + } + } + } + + function getLiveStreamMediaInfo(player, streamInfo, mediaSource, liveStreamId, serverId) { + + console.log('getLiveStreamMediaInfo'); + + streamInfo.lastMediaInfoQuery = new Date().getTime(); + + var apiClient = connectionManager.getApiClient(serverId); + + if (!apiClient.isMinServerVersion('3.2.70.7')) { + return; + } + + connectionManager.getApiClient(serverId).getLiveStreamMediaInfo(liveStreamId).then(function (info) { + + mediaSource.MediaStreams = info.MediaStreams; + events.trigger(player, 'mediastreamschange'); + + }, function () { + + }); + } + + self.onAppClose = function () { + + var player = this._currentPlayer; + + // Try to report playback stopped before the app closes + if (player && this.isPlaying(player)) { + this._playNextAfterEnded = false; + onPlaybackStopped.call(player); + } + }; + + self.playbackStartTime = function (player) { + + player = player || this._currentPlayer; + if (player && !enableLocalPlaylistManagement(player) && !player.isLocalPlayer) { + return player.playbackStartTime(); + } + + var streamInfo = getPlayerData(player).streamInfo; + return streamInfo ? streamInfo.playbackStartTimeTicks : null; + }; + + if (apphost.supports('remotecontrol')) { + + require(['serverNotifications'], function (serverNotifications) { + events.on(serverNotifications, 'ServerShuttingDown', self.setDefaultPlayerActive.bind(self)); + events.on(serverNotifications, 'ServerRestarting', self.setDefaultPlayerActive.bind(self)); + }); + } + } + + PlaybackManager.prototype.getCurrentPlayer = function () { + return this._currentPlayer; + }; + + PlaybackManager.prototype.currentTime = function (player) { + + player = player || this._currentPlayer; + if (player && !enableLocalPlaylistManagement(player) && !player.isLocalPlayer) { + return player.currentTime(); + } + + return this.getCurrentTicks(player); + }; + + PlaybackManager.prototype.nextItem = function (player) { + + player = player || this._currentPlayer; + + if (player && !enableLocalPlaylistManagement(player)) { + return player.nextItem(); + } + + var nextItem = this._playQueueManager.getNextItemInfo(); + + if (!nextItem || !nextItem.item) { + return Promise.reject(); + } + + var apiClient = connectionManager.getApiClient(nextItem.item.ServerId); + return apiClient.getItem(apiClient.getCurrentUserId(), nextItem.item.Id); + }; + + PlaybackManager.prototype.canQueue = function (item) { + + if (item.Type === 'MusicAlbum' || item.Type === 'MusicArtist' || item.Type === 'MusicGenre') { + return this.canQueueMediaType('Audio'); + } + return this.canQueueMediaType(item.MediaType); + }; + + PlaybackManager.prototype.canQueueMediaType = function (mediaType) { + + if (this._currentPlayer) { + return this._currentPlayer.canPlayMediaType(mediaType); + } + + return false; + }; + + PlaybackManager.prototype.isMuted = function (player) { + + player = player || this._currentPlayer; + + if (player) { + return player.isMuted(); + } + + return false; + }; + + PlaybackManager.prototype.setMute = function (mute, player) { + + player = player || this._currentPlayer; + + if (player) { + player.setMute(mute); + } + }; + + PlaybackManager.prototype.toggleMute = function (mute, player) { + + player = player || this._currentPlayer; + if (player) { + + if (player.toggleMute) { + player.toggleMute(); + } else { + player.setMute(!player.isMuted()); + } + } + }; + + PlaybackManager.prototype.toggleDisplayMirroring = function () { + this.enableDisplayMirroring(!this.enableDisplayMirroring()); + }; + + PlaybackManager.prototype.enableDisplayMirroring = function (enabled) { + + if (enabled != null) { + + var val = enabled ? '1' : '0'; + appSettings.set('displaymirror', val); + return; + } + + return (appSettings.get('displaymirror') || '') !== '0'; + }; + + PlaybackManager.prototype.nextChapter = function (player) { + + player = player || this._currentPlayer; + var item = this.currentItem(player); + + var ticks = this.getCurrentTicks(player); + + var nextChapter = (item.Chapters || []).filter(function (i) { + + return i.StartPositionTicks > ticks; + + })[0]; + + if (nextChapter) { + this.seek(nextChapter.StartPositionTicks, player); + } else { + this.nextTrack(player); + } + }; + + PlaybackManager.prototype.previousChapter = function (player) { + + player = player || this._currentPlayer; + var item = this.currentItem(player); + + var ticks = this.getCurrentTicks(player); + + // Go back 10 seconds + ticks -= 100000000; + + // If there's no previous track, then at least rewind to beginning + if (this.getCurrentPlaylistIndex(player) === 0) { + ticks = Math.max(ticks, 0); + } + + var previousChapters = (item.Chapters || []).filter(function (i) { + + return i.StartPositionTicks <= ticks; + }); + + if (previousChapters.length) { + this.seek(previousChapters[previousChapters.length - 1].StartPositionTicks, player); + } else { + this.previousTrack(player); + } + }; + + PlaybackManager.prototype.fastForward = function (player) { + + player = player || this._currentPlayer; + + if (player.fastForward != null) { + player.fastForward(userSettings.skipForwardLength()); + return; + } + + // Go back 15 seconds + var offsetTicks = userSettings.skipForwardLength() * 10000; + + this.seekRelative(offsetTicks, player); + }; + + PlaybackManager.prototype.rewind = function (player) { + + player = player || this._currentPlayer; + + if (player.rewind != null) { + player.rewind(userSettings.skipBackLength()); + return; + } + + // Go back 15 seconds + var offsetTicks = 0 - (userSettings.skipBackLength() * 10000); + + this.seekRelative(offsetTicks, player); + }; + + PlaybackManager.prototype.seekPercent = function (percent, player) { + + player = player || this._currentPlayer; + + var ticks = this.duration(player) || 0; + + percent /= 100; + ticks *= percent; + this.seek(parseInt(ticks), player); + }; + + PlaybackManager.prototype.playTrailers = function (item) { + + var player = this._currentPlayer; + + if (player && player.playTrailers) { + return player.playTrailers(item); + } + + var apiClient = connectionManager.getApiClient(item.ServerId); + var instance = this; - apiClient.getInstantMixFromItem(item.Id, options).then(function(result) { + + if (item.LocalTrailerCount) { + return apiClient.getLocalTrailers(apiClient.getCurrentUserId(), item.Id).then(function (result) { + return instance.play({ + items: result + }); + }); + } else { + var remoteTrailers = item.RemoteTrailers || []; + + if (!remoteTrailers.length) { + return Promise.reject(); + } + + return this.play({ + items: remoteTrailers.map(function (t) { + return { + Name: t.Name || (item.Name + ' Trailer'), + Url: t.Url, + MediaType: 'Video', + Type: 'Trailer', + ServerId: apiClient.serverId() + }; + }) + }); + } + }; + + PlaybackManager.prototype.getSubtitleUrl = function (textStream, serverId) { + + var apiClient = connectionManager.getApiClient(serverId); + var textStreamUrl = !textStream.IsExternalUrl ? apiClient.getUrl(textStream.DeliveryUrl) : textStream.DeliveryUrl; + return textStreamUrl; + }; + + PlaybackManager.prototype.stop = function (player) { + + player = player || this._currentPlayer; + + if (player) { + + if (enableLocalPlaylistManagement(player)) { + this._playNextAfterEnded = false; + } + + // TODO: remove second param + return player.stop(true, true); + } + + return Promise.resolve(); + }; + + PlaybackManager.prototype.getBufferedRanges = function (player) { + + player = player || this._currentPlayer; + + if (player) { + + if (player.getBufferedRanges) { + return player.getBufferedRanges(); + } + } + + return []; + }; + + PlaybackManager.prototype.playPause = function (player) { + + player = player || this._currentPlayer; + + if (player) { + + if (player.playPause) { + return player.playPause(); + } + + if (player.paused()) { + return this.unpause(player); + } else { + return this.pause(player); + } + } + }; + + PlaybackManager.prototype.paused = function (player) { + + player = player || this._currentPlayer; + + if (player) { + return player.paused(); + } + }; + + PlaybackManager.prototype.pause = function (player) { + player = player || this._currentPlayer; + + if (player) { + player.pause(); + } + }; + + PlaybackManager.prototype.unpause = function (player) { + player = player || this._currentPlayer; + + if (player) { + player.unpause(); + } + }; + + PlaybackManager.prototype.instantMix = function (item, player) { + + player = player || this._currentPlayer; + if (player && player.instantMix) { + return player.instantMix(item); + } + + var apiClient = connectionManager.getApiClient(item.ServerId); + + var options = {}; + options.UserId = apiClient.getCurrentUserId(); + options.Limit = 200; + + var instance = this; + + apiClient.getInstantMixFromItem(item.Id, options).then(function (result) { instance.play({ items: result.Items - }) - }) - }, PlaybackManager.prototype.shuffle = function(shuffleItem, player, queryOptions) { - return player = player || this._currentPlayer, player && player.shuffle ? player.shuffle(shuffleItem) : this.play({ - items: [shuffleItem], - shuffle: !0 - }) - }, PlaybackManager.prototype.audioTracks = function(player) { - if (player = player || this._currentPlayer, player.audioTracks) { + }); + }); + }; + + PlaybackManager.prototype.shuffle = function (shuffleItem, player, queryOptions) { + + player = player || this._currentPlayer; + if (player && player.shuffle) { + return player.shuffle(shuffleItem); + } + + return this.play({ items: [shuffleItem], shuffle: true }); + }; + + PlaybackManager.prototype.audioTracks = function (player) { + + player = player || this._currentPlayer; + if (player.audioTracks) { var result = player.audioTracks(); - if (result) return result + if (result) { + return result; + } } - return ((this.currentMediaSource(player) || {}).MediaStreams || []).filter(function(s) { - return "Audio" === s.Type - }) - }, PlaybackManager.prototype.subtitleTracks = function(player) { - if (player = player || this._currentPlayer, player.subtitleTracks) { + + var mediaSource = this.currentMediaSource(player); + + var mediaStreams = (mediaSource || {}).MediaStreams || []; + return mediaStreams.filter(function (s) { + return s.Type === 'Audio'; + }); + }; + + PlaybackManager.prototype.subtitleTracks = function (player) { + + player = player || this._currentPlayer; + if (player.subtitleTracks) { var result = player.subtitleTracks(); - if (result) return result + if (result) { + return result; + } } - return ((this.currentMediaSource(player) || {}).MediaStreams || []).filter(function(s) { - return "Subtitle" === s.Type - }) - }, PlaybackManager.prototype.getSupportedCommands = function(player) { - if (player = player || this._currentPlayer || { - isLocalPlayer: !0 - }, player.isLocalPlayer) { - var list = ["GoHome", "GoToSettings", "VolumeUp", "VolumeDown", "Mute", "Unmute", "ToggleMute", "SetVolume", "SetAudioStreamIndex", "SetSubtitleStreamIndex", "SetMaxStreamingBitrate", "DisplayContent", "GoToSearch", "DisplayMessage", "SetRepeatMode", "PlayMediaSource", "PlayTrailers"]; - return apphost.supports("fullscreenchange") && list.push("ToggleFullscreen"), player.supports && (player.supports("PictureInPicture") && list.push("PictureInPicture"), player.supports("SetBrightness") && list.push("SetBrightness"), player.supports("SetAspectRatio") && list.push("SetAspectRatio")), list + + var mediaSource = this.currentMediaSource(player); + + var mediaStreams = (mediaSource || {}).MediaStreams || []; + return mediaStreams.filter(function (s) { + return s.Type === 'Subtitle'; + }); + }; + + PlaybackManager.prototype.getSupportedCommands = function (player) { + + player = player || this._currentPlayer || { isLocalPlayer: true }; + + if (player.isLocalPlayer) { + // Full list + // https://github.com/MediaBrowser/MediaBrowser/blob/master/MediaBrowser.Model/Session/GeneralCommand.cs + var list = [ + "GoHome", + "GoToSettings", + "VolumeUp", + "VolumeDown", + "Mute", + "Unmute", + "ToggleMute", + "SetVolume", + "SetAudioStreamIndex", + "SetSubtitleStreamIndex", + "SetMaxStreamingBitrate", + "DisplayContent", + "GoToSearch", + "DisplayMessage", + "SetRepeatMode", + "PlayMediaSource", + "PlayTrailers" + ]; + + if (apphost.supports('fullscreenchange')) { + list.push('ToggleFullscreen'); + } + + if (player.supports) { + if (player.supports('PictureInPicture')) { + list.push('PictureInPicture'); + } + if (player.supports('SetBrightness')) { + list.push('SetBrightness'); + } + if (player.supports('SetAspectRatio')) { + list.push('SetAspectRatio'); + } + } + + return list; } + var info = this.getPlayerInfo(); - return info ? info.supportedCommands : [] - }, PlaybackManager.prototype.setRepeatMode = function(value, player) { - if ((player = player || this._currentPlayer) && !enableLocalPlaylistManagement(player)) return player.setRepeatMode(value); - this._playQueueManager.setRepeatMode(value), events.trigger(player, "repeatmodechange") - }, PlaybackManager.prototype.getRepeatMode = function(player) { - return player = player || this._currentPlayer, player && !enableLocalPlaylistManagement(player) ? player.getRepeatMode() : this._playQueueManager.getRepeatMode() - }, PlaybackManager.prototype.trySetActiveDeviceName = function(name) { + return info ? info.supportedCommands : []; + }; + + PlaybackManager.prototype.setRepeatMode = function (value, player) { + + player = player || this._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.setRepeatMode(value); + } + + this._playQueueManager.setRepeatMode(value); + events.trigger(player, 'repeatmodechange'); + }; + + PlaybackManager.prototype.getRepeatMode = function (player) { + + player = player || this._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.getRepeatMode(); + } + + return this._playQueueManager.getRepeatMode(); + }; + + PlaybackManager.prototype.trySetActiveDeviceName = function (name) { + name = normalizeName(name); + var instance = this; - instance.getTargets().then(function(result) { - var target = result.filter(function(p) { - return normalizeName(p.name) === name + instance.getTargets().then(function (result) { + + var target = result.filter(function (p) { + return normalizeName(p.name) === name; })[0]; - target && instance.trySetActivePlayer(target.playerName, target) - }) - }, PlaybackManager.prototype.displayContent = function(options, player) { - (player = player || this._currentPlayer) && player.displayContent && player.displayContent(options) - }, PlaybackManager.prototype.beginPlayerUpdates = function(player) { - player.beginPlayerUpdates && player.beginPlayerUpdates() - }, PlaybackManager.prototype.endPlayerUpdates = function(player) { - player.endPlayerUpdates && player.endPlayerUpdates() - }, PlaybackManager.prototype.setDefaultPlayerActive = function() { - this.setActivePlayer("localplayer") - }, PlaybackManager.prototype.removeActivePlayer = function(name) { + + if (target) { + instance.trySetActivePlayer(target.playerName, target); + } + + }); + }; + + PlaybackManager.prototype.displayContent = function (options, player) { + player = player || this._currentPlayer; + if (player && player.displayContent) { + player.displayContent(options); + } + }; + + PlaybackManager.prototype.beginPlayerUpdates = function (player) { + if (player.beginPlayerUpdates) { + player.beginPlayerUpdates(); + } + }; + + PlaybackManager.prototype.endPlayerUpdates = function (player) { + if (player.endPlayerUpdates) { + player.endPlayerUpdates(); + } + }; + + PlaybackManager.prototype.setDefaultPlayerActive = function () { + + this.setActivePlayer('localplayer'); + }; + + PlaybackManager.prototype.removeActivePlayer = function (name) { + var playerInfo = this.getPlayerInfo(); - playerInfo && playerInfo.name === name && this.setDefaultPlayerActive() - }, PlaybackManager.prototype.removeActiveTarget = function(id) { + if (playerInfo) { + if (playerInfo.name === name) { + this.setDefaultPlayerActive(); + } + } + }; + + PlaybackManager.prototype.removeActiveTarget = function (id) { + var playerInfo = this.getPlayerInfo(); - playerInfo && playerInfo.id === id && this.setDefaultPlayerActive() - }, PlaybackManager.prototype.sendCommand = function(cmd, player) { - switch (console.log("MediaController received command: " + cmd.Name), cmd.Name) { - case "SetRepeatMode": + if (playerInfo) { + if (playerInfo.id === id) { + this.setDefaultPlayerActive(); + } + } + }; + + PlaybackManager.prototype.sendCommand = function (cmd, player) { + + // Full list + // https://github.com/MediaBrowser/MediaBrowser/blob/master/MediaBrowser.Model/Session/GeneralCommand.cs#L23 + console.log('MediaController received command: ' + cmd.Name); + switch (cmd.Name) { + + case 'SetRepeatMode': this.setRepeatMode(cmd.Arguments.RepeatMode, player); break; - case "VolumeUp": + case 'VolumeUp': this.volumeUp(player); break; - case "VolumeDown": + case 'VolumeDown': this.volumeDown(player); break; - case "Mute": - this.setMute(!0, player); + case 'Mute': + this.setMute(true, player); break; - case "Unmute": - this.setMute(!1, player); + case 'Unmute': + this.setMute(false, player); break; - case "ToggleMute": + case 'ToggleMute': this.toggleMute(player); break; - case "SetVolume": + case 'SetVolume': this.setVolume(cmd.Arguments.Volume, player); break; - case "SetAspectRatio": + case 'SetAspectRatio': this.setAspectRatio(cmd.Arguments.AspectRatio, player); break; - case "SetBrightness": + case 'SetBrightness': this.setBrightness(cmd.Arguments.Brightness, player); break; - case "SetAudioStreamIndex": + case 'SetAudioStreamIndex': this.setAudioStreamIndex(parseInt(cmd.Arguments.Index), player); break; - case "SetSubtitleStreamIndex": + case 'SetSubtitleStreamIndex': this.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index), player); break; - case "SetMaxStreamingBitrate": + case 'SetMaxStreamingBitrate': + // todo + //this.setMaxStreamingBitrate(parseInt(cmd.Arguments.Bitrate), player); break; - case "ToggleFullscreen": + case 'ToggleFullscreen': this.toggleFullscreen(player); break; default: - player.sendCommand && player.sendCommand(cmd) + { + if (player.sendCommand) { + player.sendCommand(cmd); + } + break; + } } - }, new PlaybackManager + }; + + return new PlaybackManager(); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/playbackorientation.js b/src/bower_components/emby-webcomponents/playback/playbackorientation.js index b682f7c564..30997dbdac 100644 --- a/src/bower_components/emby-webcomponents/playback/playbackorientation.js +++ b/src/bower_components/emby-webcomponents/playback/playbackorientation.js @@ -1,35 +1,57 @@ -define(["playbackManager", "layoutManager", "events"], function(playbackManager, layoutManager, events) { +define(['playbackManager', 'layoutManager', 'events'], function (playbackManager, layoutManager, events) { "use strict"; + var orientationLocked; + function onOrientationChangeSuccess() { - orientationLocked = !0 + orientationLocked = true; } function onOrientationChangeError(err) { - orientationLocked = !1, console.log("error locking orientation: " + err) + orientationLocked = false; + console.log('error locking orientation: ' + err); } - var orientationLocked; - events.on(playbackManager, "playbackstart", function(e, player, state) { - if (player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player) && layoutManager.mobile) { - var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || screen.orientation && screen.orientation.lock; - if (lockOrientation) try { - var promise = lockOrientation("landscape"); - promise.then ? promise.then(onOrientationChangeSuccess, onOrientationChangeError) : orientationLocked = promise - } catch (err) { - onOrientationChangeError(err) + + events.on(playbackManager, 'playbackstart', function (e, player, state) { + + var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player); + + if (isLocalVideo && layoutManager.mobile) { + var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || (screen.orientation && screen.orientation.lock); + + if (lockOrientation) { + + try { + var promise = lockOrientation('landscape'); + if (promise.then) { + promise.then(onOrientationChangeSuccess, onOrientationChangeError); + } else { + // returns a boolean + orientationLocked = promise; + } + } + catch (err) { + onOrientationChangeError(err); + } } } - }), events.on(playbackManager, "playbackstop", function(e, playbackStopInfo) { + }); + + events.on(playbackManager, 'playbackstop', function (e, playbackStopInfo) { + if (orientationLocked && !playbackStopInfo.nextMediaType) { - var unlockOrientation = screen.unlockOrientation || screen.mozUnlockOrientation || screen.msUnlockOrientation || screen.orientation && screen.orientation.unlock; + + var unlockOrientation = screen.unlockOrientation || screen.mozUnlockOrientation || screen.msUnlockOrientation || (screen.orientation && screen.orientation.unlock); + if (unlockOrientation) { try { - unlockOrientation() - } catch (err) { - console.log("error unlocking orientation: " + err) + unlockOrientation(); } - orientationLocked = !1 + catch (err) { + console.log('error unlocking orientation: ' + err); + } + orientationLocked = false; } } - }) + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/playbackvalidation.js b/src/bower_components/emby-webcomponents/playback/playbackvalidation.js index 6fa070ab3b..c36d5c1b5a 100644 --- a/src/bower_components/emby-webcomponents/playback/playbackvalidation.js +++ b/src/bower_components/emby-webcomponents/playback/playbackvalidation.js @@ -1,43 +1,80 @@ -define(["playbackManager", "itemHelper"], function(playbackManager, itemHelper) { +define(['playbackManager', 'itemHelper'], function (playbackManager, itemHelper) { "use strict"; function getRequirePromise(deps) { - return new Promise(function(resolve, reject) { - require(deps, resolve) - }) + + return new Promise(function (resolve, reject) { + + require(deps, resolve); + }); } function validatePlayback(options) { - var feature = "playback"; - if (!options.item || "TvChannel" !== options.item.Type && "Recording" !== options.item.Type || (feature = "livetv"), "playback" === feature) { - var player = playbackManager.getCurrentPlayer(); - if (player && !player.isLocalPlayer) return Promise.resolve() + + var feature = 'playback'; + if (options.item && (options.item.Type === 'TvChannel' || options.item.Type === 'Recording')) { + feature = 'livetv'; } - return getRequirePromise(["registrationServices"]).then(function(registrationServices) { - return registrationServices.validateFeature(feature, options).then(function(result) { - result && result.enableTimeLimit && startAutoStopTimer() - }) - }) + + if (feature === 'playback') { + var player = playbackManager.getCurrentPlayer(); + if (player && !player.isLocalPlayer) { + return Promise.resolve(); + } + } + + return getRequirePromise(["registrationServices"]).then(function (registrationServices) { + + return registrationServices.validateFeature(feature, options).then(function (result) { + + if (result && result.enableTimeLimit) { + startAutoStopTimer(); + } + }); + }); } + var autoStopTimeout; function startAutoStopTimer() { - stopAutoStopTimer(), autoStopTimeout = setTimeout(onAutoStopTimeout, 63e3) + stopAutoStopTimer(); + autoStopTimeout = setTimeout(onAutoStopTimeout, 63000); } function onAutoStopTimeout() { - stopAutoStopTimer(), playbackManager.stop() + stopAutoStopTimer(); + playbackManager.stop(); } function stopAutoStopTimer() { + var timeout = autoStopTimeout; - timeout && (clearTimeout(timeout), autoStopTimeout = null) + if (timeout) { + clearTimeout(timeout); + autoStopTimeout = null; + } } function PlaybackValidation() { - this.name = "Playback validation", this.type = "preplayintercept", this.id = "playbackvalidation", this.order = -1 + + this.name = 'Playback validation'; + this.type = 'preplayintercept'; + this.id = 'playbackvalidation'; + this.order = -1; } - var autoStopTimeout; - return PlaybackValidation.prototype.intercept = function(options) { - return options.fullscreen ? options.item && itemHelper.isLocalItem(options.item) ? Promise.resolve() : validatePlayback(options) : Promise.resolve() - }, PlaybackValidation + + PlaybackValidation.prototype.intercept = function (options) { + + // Don't care about video backdrops, or theme music or any kind of non-fullscreen playback + if (!options.fullscreen) { + return Promise.resolve(); + } + + if (options.item && itemHelper.isLocalItem(options.item)) { + return Promise.resolve(); + } + + return validatePlayback(options); + }; + + return PlaybackValidation; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/playerselection.js b/src/bower_components/emby-webcomponents/playback/playerselection.js index 0a2445f676..86a0b9daab 100644 --- a/src/bower_components/emby-webcomponents/playback/playerselection.js +++ b/src/bower_components/emby-webcomponents/playback/playerselection.js @@ -1,158 +1,323 @@ -define(["appSettings", "events", "browser", "loading", "playbackManager", "appRouter", "globalize", "apphost"], function(appSettings, events, browser, loading, playbackManager, appRouter, globalize, appHost) { - "use strict"; +define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRouter', 'globalize', 'apphost'], function (appSettings, events, browser, loading, playbackManager, appRouter, globalize, appHost) { + 'use strict'; function mirrorItem(info, player) { + var item = info.item; + playbackManager.displayContent({ + ItemName: item.Name, ItemId: item.Id, ItemType: item.Type, Context: info.context - }, player) + }, player); } function mirrorIfEnabled(info) { + if (info && playbackManager.enableDisplayMirroring()) { + var getPlayerInfo = playbackManager.getPlayerInfo(); - getPlayerInfo && (getPlayerInfo.isLocalPlayer || -1 === getPlayerInfo.supportedCommands.indexOf("DisplayContent") || mirrorItem(info, playbackManager.getCurrentPlayer())) + + if (getPlayerInfo) { + if (!getPlayerInfo.isLocalPlayer && getPlayerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { + mirrorItem(info, playbackManager.getCurrentPlayer()); + } + } } } - function emptyCallback() {} + function emptyCallback() { + // avoid console logs about uncaught promises + } function getTargetSecondaryText(target) { - return target.user ? target.user.Name : null + + if (target.user) { + + return target.user.Name; + } + + return null; } function getIcon(target) { + var deviceType = target.deviceType; - switch (!deviceType && target.isLocalPlayer && (deviceType = browser.tv ? "tv" : browser.mobile ? "smartphone" : "desktop"), deviceType || (deviceType = "tv"), deviceType) { - case "smartphone": - return ""; - case "tablet": - return ""; - case "tv": - return ""; - case "cast": - return ""; - case "desktop": - return ""; + + if (!deviceType && target.isLocalPlayer) { + if (browser.tv) { + deviceType = 'tv'; + } else if (browser.mobile) { + deviceType = 'smartphone'; + } else { + deviceType = 'desktop'; + } + } + + if (!deviceType) { + deviceType = 'tv'; + } + + switch (deviceType) { + + case 'smartphone': + return ''; + case 'tablet': + return ''; + case 'tv': + return ''; + case 'cast': + return ''; + case 'desktop': + return ''; default: - return "" + return ''; } } function showPlayerSelection(button) { + var currentPlayerInfo = playbackManager.getPlayerInfo(); - if (currentPlayerInfo && !currentPlayerInfo.isLocalPlayer) return void showActivePlayerMenu(currentPlayerInfo); + + if (currentPlayerInfo) { + if (!currentPlayerInfo.isLocalPlayer) { + showActivePlayerMenu(currentPlayerInfo); + return; + } + } + var currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null; - loading.show(), playbackManager.getTargets().then(function(targets) { - var menuItems = targets.map(function(t) { + + loading.show(); + + playbackManager.getTargets().then(function (targets) { + + var menuItems = targets.map(function (t) { + var name = t.name; - return t.appName && t.appName !== t.name && (name += " - " + t.appName), { + + if (t.appName && t.appName !== t.name) { + name += " - " + t.appName; + } + + return { name: name, id: t.id, selected: currentPlayerId === t.id, secondaryText: getTargetSecondaryText(t), icon: getIcon(t) - } + }; + }); - require(["actionsheet"], function(actionsheet) { + + require(['actionsheet'], function (actionsheet) { + loading.hide(); + var menuOptions = { - title: globalize.translate("sharedcomponents#HeaderPlayOn"), + title: globalize.translate('sharedcomponents#HeaderPlayOn'), items: menuItems, positionTo: button, - resolveOnClick: !0, - border: !0 + + resolveOnClick: true, + border: true }; - browser.chrome && !appHost.supports("castmenuhashchange") && (menuOptions.enableHistory = !1), actionsheet.show(menuOptions).then(function(id) { - var target = targets.filter(function(t) { - return t.id === id + + // Unfortunately we can't allow the url to change or chromecast will throw a security error + // Might be able to solve this in the future by moving the dialogs to hashbangs + if (!(!browser.chrome || appHost.supports('castmenuhashchange'))) { + menuOptions.enableHistory = false; + } + + actionsheet.show(menuOptions).then(function (id) { + + var target = targets.filter(function (t) { + return t.id === id; })[0]; - playbackManager.trySetActivePlayer(target.playerName, target), mirrorIfEnabled() - }, emptyCallback) - }) - }) + + playbackManager.trySetActivePlayer(target.playerName, target); + + mirrorIfEnabled(); + + }, emptyCallback); + }); + }); } function showActivePlayerMenu(playerInfo) { - require(["dialogHelper", "dialog", "emby-checkbox", "emby-button"], function(dialogHelper) { - showActivePlayerMenuInternal(dialogHelper, playerInfo) - }) + + require(['dialogHelper', 'dialog', 'emby-checkbox', 'emby-button'], function (dialogHelper) { + showActivePlayerMenuInternal(dialogHelper, playerInfo); + }); } + function disconnectFromPlayer(currentDeviceName) { - -1 !== playbackManager.getSupportedCommands().indexOf("EndSession") ? require(["dialog"], function(dialog) { - var menuItems = []; - menuItems.push({ - name: globalize.translate("sharedcomponents#Yes"), - id: "yes" - }), menuItems.push({ - name: globalize.translate("sharedcomponents#No"), - id: "no" - }), dialog({ - buttons: menuItems, - text: globalize.translate("sharedcomponents#ConfirmEndPlayerSession", currentDeviceName) - }).then(function(id) { - switch (id) { - case "yes": - playbackManager.getCurrentPlayer().endSession(), playbackManager.setDefaultPlayerActive(); - break; - case "no": - playbackManager.setDefaultPlayerActive() - } - }) - }) : playbackManager.setDefaultPlayerActive() + + if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) { + + require(['dialog'], function (dialog) { + + var menuItems = []; + + menuItems.push({ + name: globalize.translate('sharedcomponents#Yes'), + id: 'yes' + }); + menuItems.push({ + name: globalize.translate('sharedcomponents#No'), + id: 'no' + }); + + dialog({ + buttons: menuItems, + //positionTo: positionTo, + text: globalize.translate('sharedcomponents#ConfirmEndPlayerSession', currentDeviceName) + + }).then(function (id) { + switch (id) { + + case 'yes': + playbackManager.getCurrentPlayer().endSession(); + playbackManager.setDefaultPlayerActive(); + break; + case 'no': + playbackManager.setDefaultPlayerActive(); + break; + default: + break; + } + }); + + }); + + + } else { + + playbackManager.setDefaultPlayerActive(); + } } function showActivePlayerMenuInternal(dialogHelper, playerInfo) { - var html = "", - dialogOptions = { - removeOnClose: !0 - }; - dialogOptions.modal = !1, dialogOptions.entryAnimationDuration = 160, dialogOptions.exitAnimationDuration = 160, dialogOptions.autoFocus = !1; + + var html = ''; + + var dialogOptions = { + removeOnClose: true + }; + + dialogOptions.modal = false; + dialogOptions.entryAnimationDuration = 160; + dialogOptions.exitAnimationDuration = 160; + dialogOptions.autoFocus = false; + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("promptDialog"); - var currentDeviceName = playerInfo.deviceName || playerInfo.name; - if (html += '
', html += '

', html += currentDeviceName, html += "

", html += "
", -1 !== playerInfo.supportedCommands.indexOf("DisplayContent")) { + + dlg.classList.add('promptDialog'); + + var currentDeviceName = (playerInfo.deviceName || playerInfo.name); + + html += '
'; + html += '

'; + html += currentDeviceName; + html += '

'; + + html += '
'; + + if (playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { + html += '" + var checkedHtml = playbackManager.enableDisplayMirroring() ? ' checked' : ''; + html += ''; + html += '' + globalize.translate('sharedcomponents#EnableDisplayMirroring') + ''; + html += ''; } - html += "
", html += '
', html += '", html += '", html += '", html += "
", html += "
", dlg.innerHTML = html; - var chkMirror = dlg.querySelector(".chkMirror"); - chkMirror && chkMirror.addEventListener("change", onMirrorChange); - var destination = "", - btnRemoteControl = dlg.querySelector(".btnRemoteControl"); - btnRemoteControl && btnRemoteControl.addEventListener("click", function() { - destination = "nowplaying", dialogHelper.close(dlg) - }), dlg.querySelector(".btnDisconnect").addEventListener("click", function() { - destination = "disconnectFromPlayer", dialogHelper.close(dlg) - }), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), dialogHelper.open(dlg).then(function() { - "nowplaying" === destination ? appRouter.showNowPlaying() : "disconnectFromPlayer" === destination && disconnectFromPlayer(currentDeviceName) - }, emptyCallback) + + html += '
'; + + html += '
'; + + html += ''; + html += ''; + html += ''; + html += '
'; + + html += '
'; + dlg.innerHTML = html; + + var chkMirror = dlg.querySelector('.chkMirror'); + + if (chkMirror) { + chkMirror.addEventListener('change', onMirrorChange); + } + + var destination = ''; + + var btnRemoteControl = dlg.querySelector('.btnRemoteControl'); + if (btnRemoteControl) { + btnRemoteControl.addEventListener('click', function () { + destination = 'nowplaying'; + dialogHelper.close(dlg); + }); + } + + dlg.querySelector('.btnDisconnect').addEventListener('click', function () { + destination = 'disconnectFromPlayer'; + dialogHelper.close(dlg); + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + dialogHelper.close(dlg); + }); + + dialogHelper.open(dlg).then(function () { + if (destination === 'nowplaying') { + appRouter.showNowPlaying(); + } + else if (destination === 'disconnectFromPlayer') { + disconnectFromPlayer(currentDeviceName); + } + }, emptyCallback); } function onMirrorChange() { - playbackManager.enableDisplayMirroring(this.checked) + playbackManager.enableDisplayMirroring(this.checked); } - return document.addEventListener("viewshow", function(e) { - var state = e.detail.state || {}, - item = state.item; - if (item && item.ServerId) return void mirrorIfEnabled({ - item: item - }) - }), events.on(appSettings, "change", function(e, name) { - "displaymirror" === name && mirrorIfEnabled() - }), events.on(playbackManager, "pairing", function(e) { - loading.show() - }), events.on(playbackManager, "paired", function(e) { - loading.hide() - }), events.on(playbackManager, "pairerror", function(e) { - loading.hide() - }), { + + document.addEventListener('viewshow', function (e) { + + var state = e.detail.state || {}; + var item = state.item; + + if (item && item.ServerId) { + mirrorIfEnabled({ + item: item + }); + return; + } + }); + + events.on(appSettings, 'change', function (e, name) { + if (name === 'displaymirror') { + mirrorIfEnabled(); + } + }); + + events.on(playbackManager, 'pairing', function (e) { + loading.show(); + }); + + events.on(playbackManager, 'paired', function (e) { + loading.hide(); + }); + + events.on(playbackManager, 'pairerror', function (e) { + loading.hide(); + }); + + return { show: showPlayerSelection - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/playersettingsmenu.js b/src/bower_components/emby-webcomponents/playback/playersettingsmenu.js index f75ad2a65b..00d05d9d2b 100644 --- a/src/bower_components/emby-webcomponents/playback/playersettingsmenu.js +++ b/src/bower_components/emby-webcomponents/playback/playersettingsmenu.js @@ -1,195 +1,315 @@ -define(["connectionManager", "actionsheet", "datetime", "playbackManager", "globalize", "appSettings", "qualityoptions"], function(connectionManager, actionsheet, datetime, playbackManager, globalize, appSettings, qualityoptions) { - "use strict"; +define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'globalize', 'appSettings', 'qualityoptions'], function (connectionManager, actionsheet, datetime, playbackManager, globalize, appSettings, qualityoptions) { + 'use strict'; function showQualityMenu(player, btn) { - var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function(stream) { - return "Video" === stream.Type - })[0], - videoWidth = videoStream ? videoStream.Width : null, - options = qualityoptions.getVideoQualityOptions({ - currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), - isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), - videoWidth: videoWidth, - enableAuto: !0 - }), - menuItems = options.map(function(o) { - var opt = { - name: o.name, - id: o.bitrate, - asideText: o.secondaryText - }; - return o.selected && (opt.selected = !0), opt - }), - selectedId = options.filter(function(o) { - return o.selected - }); - return selectedId = selectedId.length ? selectedId[0].bitrate : null, actionsheet.show({ - items: menuItems, - positionTo: btn - }).then(function(id) { - var bitrate = parseInt(id); - bitrate !== selectedId && playbackManager.setMaxStreamingBitrate({ - enableAutomaticBitrateDetection: !bitrate, - maxBitrate: bitrate - }, player) - }) - } - function showRepeatModeMenu(player, btn) { - var menuItems = [], - currentValue = playbackManager.getRepeatMode(player); - return menuItems.push({ - name: globalize.translate("sharedcomponents#RepeatAll"), - id: "RepeatAll", - selected: "RepeatAll" === currentValue - }), menuItems.push({ - name: globalize.translate("sharedcomponents#RepeatOne"), - id: "RepeatOne", - selected: "RepeatOne" === currentValue - }), menuItems.push({ - name: globalize.translate("sharedcomponents#None"), - id: "RepeatNone", - selected: "RepeatNone" === currentValue - }), actionsheet.show({ - items: menuItems, - positionTo: btn - }).then(function(mode) { - mode && playbackManager.setRepeatMode(mode, player) - }) - } + var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { + return stream.Type === "Video"; + })[0]; + var videoWidth = videoStream ? videoStream.Width : null; - function getQualitySecondaryText(player) { - var state = playbackManager.getPlayerState(player), - videoStream = (playbackManager.enableAutomaticBitrateDetection(player), playbackManager.getMaxStreamingBitrate(player), playbackManager.currentMediaSource(player).MediaStreams.filter(function(stream) { - return "Video" === stream.Type - })[0]), - videoWidth = videoStream ? videoStream.Width : null, - options = qualityoptions.getVideoQualityOptions({ - currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), - isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), - videoWidth: videoWidth, - enableAuto: !0 - }), - selectedOption = (options.map(function(o) { - var opt = { - name: o.name, - id: o.bitrate, - asideText: o.secondaryText - }; - return o.selected && (opt.selected = !0), opt - }), options.filter(function(o) { - return o.selected - })); - if (!selectedOption.length) return null; - selectedOption = selectedOption[0]; - var text = selectedOption.name; - return selectedOption.autoText && (state.PlayState && "Transcode" !== state.PlayState.PlayMethod ? text += " - Direct" : text += " " + selectedOption.autoText), text - } + var options = qualityoptions.getVideoQualityOptions({ + currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), + isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), + videoWidth: videoWidth, + enableAuto: true + }); + + var menuItems = options.map(function (o) { + + var opt = { + name: o.name, + id: o.bitrate, + asideText: o.secondaryText + }; + + if (o.selected) { + opt.selected = true; + } + + return opt; + }); + + var selectedId = options.filter(function (o) { + return o.selected; + }); + + selectedId = selectedId.length ? selectedId[0].bitrate : null; - function showAspectRatioMenu(player, btn) { - var currentId = playbackManager.getAspectRatio(player), - menuItems = playbackManager.getSupportedAspectRatios(player).map(function(i) { - return { - id: i.id, - name: i.name, - selected: i.id === currentId - } - }); return actionsheet.show({ items: menuItems, positionTo: btn - }).then(function(id) { - return id ? (playbackManager.setAspectRatio(id, player), Promise.resolve()) : Promise.reject() - }) + + }).then(function (id) { + var bitrate = parseInt(id); + if (bitrate !== selectedId) { + + playbackManager.setMaxStreamingBitrate({ + + enableAutomaticBitrateDetection: bitrate ? false : true, + maxBitrate: bitrate + + }, player); + } + }); + } + + function showRepeatModeMenu(player, btn) { + + var menuItems = []; + + var currentValue = playbackManager.getRepeatMode(player); + + menuItems.push({ + name: globalize.translate('sharedcomponents#RepeatAll'), + id: 'RepeatAll', + selected: currentValue === 'RepeatAll' + }); + menuItems.push({ + name: globalize.translate('sharedcomponents#RepeatOne'), + id: 'RepeatOne', + selected: currentValue === 'RepeatOne' + }); + + menuItems.push({ + name: globalize.translate('sharedcomponents#None'), + id: 'RepeatNone', + selected: currentValue === 'RepeatNone' + }); + + return actionsheet.show({ + items: menuItems, + positionTo: btn + + }).then(function (mode) { + + if (mode) { + playbackManager.setRepeatMode(mode, player); + } + }); + } + + function getQualitySecondaryText(player) { + + var state = playbackManager.getPlayerState(player); + + var isAutoEnabled = playbackManager.enableAutomaticBitrateDetection(player); + var currentMaxBitrate = playbackManager.getMaxStreamingBitrate(player); + + var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { + return stream.Type === "Video"; + })[0]; + var videoWidth = videoStream ? videoStream.Width : null; + + var options = qualityoptions.getVideoQualityOptions({ + currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), + isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), + videoWidth: videoWidth, + enableAuto: true + }); + + var menuItems = options.map(function (o) { + + var opt = { + name: o.name, + id: o.bitrate, + asideText: o.secondaryText + }; + + if (o.selected) { + opt.selected = true; + } + + return opt; + }); + + var selectedOption = options.filter(function (o) { + return o.selected; + }); + + if (!selectedOption.length) { + return null; + } + + selectedOption = selectedOption[0]; + + var text = selectedOption.name; + + if (selectedOption.autoText) { + if (state.PlayState && state.PlayState.PlayMethod !== 'Transcode') { + text += ' - Direct'; + } else { + text += ' ' + selectedOption.autoText; + } + } + + return text; + } + + function showAspectRatioMenu(player, btn) { + + // Each has name/id + var currentId = playbackManager.getAspectRatio(player); + var menuItems = playbackManager.getSupportedAspectRatios(player).map(function (i) { + return { + id: i.id, + name: i.name, + selected: i.id === currentId + }; + }); + + return actionsheet.show({ + + items: menuItems, + positionTo: btn + + }).then(function (id) { + + if (id) { + playbackManager.setAspectRatio(id, player); + return Promise.resolve(); + } + + return Promise.reject(); + }); } function showWithUser(options, player, user) { - var supportedCommands = playbackManager.getSupportedCommands(player), - menuItems = (options.mediaType, []); - if (-1 !== supportedCommands.indexOf("SetAspectRatio")) { - var currentAspectRatioId = playbackManager.getAspectRatio(player), - currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function(i) { - return i.id === currentAspectRatioId - })[0]; + + var supportedCommands = playbackManager.getSupportedCommands(player); + + var mediaType = options.mediaType; + + var menuItems = []; + + if (supportedCommands.indexOf('SetAspectRatio') !== -1) { + + var currentAspectRatioId = playbackManager.getAspectRatio(player); + var currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function (i) { + return i.id === currentAspectRatioId; + })[0]; + menuItems.push({ - name: globalize.translate("sharedcomponents#AspectRatio"), - id: "aspectratio", + name: globalize.translate('sharedcomponents#AspectRatio'), + id: 'aspectratio', asideText: currentAspectRatio ? currentAspectRatio.name : null - }) + }); } - if (menuItems.push({ - name: globalize.translate("sharedcomponents#PlaybackSettings"), - id: "playbacksettings" - }), user && user.Policy.EnableVideoPlaybackTranscoding) { + + menuItems.push({ + name: globalize.translate('sharedcomponents#PlaybackSettings'), + id: 'playbacksettings' + }); + + if (user && user.Policy.EnableVideoPlaybackTranscoding) { var secondaryQualityText = getQualitySecondaryText(player); + menuItems.push({ - name: globalize.translate("sharedcomponents#Quality"), - id: "quality", + name: globalize.translate('sharedcomponents#Quality'), + id: 'quality', asideText: secondaryQualityText - }) + }); } + var repeatMode = playbackManager.getRepeatMode(player); - return -1 !== supportedCommands.indexOf("SetRepeatMode") && playbackManager.currentMediaSource(player).RunTimeTicks && menuItems.push({ - name: globalize.translate("sharedcomponents#RepeatMode"), - id: "repeatmode", - asideText: "RepeatNone" === repeatMode ? globalize.translate("sharedcomponents#None") : globalize.translate("sharedcomponents#" + repeatMode) - }), options.stats && menuItems.push({ - name: globalize.translate("sharedcomponents#StatsForNerds"), - id: "stats", - asideText: null - }), menuItems.push({ - name: globalize.translate("sharedcomponents#SubtitleSettings"), - id: "subtitlesettings" - }), actionsheet.show({ + + if (supportedCommands.indexOf('SetRepeatMode') !== -1 && playbackManager.currentMediaSource(player).RunTimeTicks) { + + menuItems.push({ + name: globalize.translate('sharedcomponents#RepeatMode'), + id: 'repeatmode', + asideText: repeatMode === 'RepeatNone' ? globalize.translate('sharedcomponents#None') : globalize.translate('sharedcomponents#' + repeatMode) + }); + } + + if (options.stats) { + + menuItems.push({ + name: globalize.translate('sharedcomponents#StatsForNerds'), + id: 'stats', + asideText: null + }); + } + + menuItems.push({ + name: globalize.translate('sharedcomponents#SubtitleSettings'), + id: 'subtitlesettings' + }); + + return actionsheet.show({ + items: menuItems, positionTo: options.positionTo - }).then(function(id) { - return handleSelectedOption(id, options, player) - }) + + }).then(function (id) { + + return handleSelectedOption(id, options, player); + }); } function show(options) { - var player = options.player, - currentItem = playbackManager.currentItem(player); - return currentItem && currentItem.ServerId ? connectionManager.getApiClient(currentItem.ServerId).getCurrentUser().then(function(user) { - return showWithUser(options, player, user) - }) : showWithUser(options, player, null) + + var player = options.player; + + var currentItem = playbackManager.currentItem(player); + + if (!currentItem || !currentItem.ServerId) { + return showWithUser(options, player, null); + } + + var apiClient = connectionManager.getApiClient(currentItem.ServerId); + + return apiClient.getCurrentUser().then(function (user) { + return showWithUser(options, player, user); + }); } function alertText(text) { - return new Promise(function(resolve, reject) { - require(["alert"], function(alert) { - alert(text).then(resolve) - }) - }) + + return new Promise(function (resolve, reject) { + + require(['alert'], function (alert) { + + alert(text).then(resolve); + }); + }); } function showSubtitleSettings(player, btn) { - return alertText(globalize.translate("sharedcomponents#SubtitleSettingsIntro")) + return alertText(globalize.translate('sharedcomponents#SubtitleSettingsIntro')); } function showPlaybackSettings(player, btn) { - return alertText(globalize.translate("sharedcomponents#PlaybackSettingsIntro")) + return alertText(globalize.translate('sharedcomponents#PlaybackSettingsIntro')); } function handleSelectedOption(id, options, player) { + switch (id) { - case "quality": + + case 'quality': return showQualityMenu(player, options.positionTo); - case "aspectratio": + case 'aspectratio': return showAspectRatioMenu(player, options.positionTo); - case "repeatmode": + case 'repeatmode': return showRepeatModeMenu(player, options.positionTo); - case "subtitlesettings": + case 'subtitlesettings': return showSubtitleSettings(player, options.positionTo); - case "playbacksettings": + case 'playbacksettings': return showPlaybackSettings(player, options.positionTo); - case "stats": - return options.onOption && options.onOption("stats"), Promise.resolve() + case 'stats': + if (options.onOption) { + options.onOption('stats'); + } + return Promise.resolve(); + default: + break; } - return Promise.reject() + + return Promise.reject(); } + return { show: show - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/playmethodhelper.js b/src/bower_components/emby-webcomponents/playback/playmethodhelper.js index 56e5f45dfa..2caae0d4cc 100644 --- a/src/bower_components/emby-webcomponents/playback/playmethodhelper.js +++ b/src/bower_components/emby-webcomponents/playback/playmethodhelper.js @@ -1,10 +1,27 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; function getDisplayPlayMethod(session) { - return session.NowPlayingItem ? session.TranscodingInfo && session.TranscodingInfo.IsVideoDirect ? "DirectStream" : "Transcode" === session.PlayState.PlayMethod ? "Transcode" : "DirectStream" === session.PlayState.PlayMethod ? "DirectPlay" : "DirectPlay" === session.PlayState.PlayMethod ? "DirectPlay" : void 0 : null + + if (!session.NowPlayingItem) { + return null; + } + + if (session.TranscodingInfo && session.TranscodingInfo.IsVideoDirect) { + return 'DirectStream'; + } + else if (session.PlayState.PlayMethod === 'Transcode') { + return 'Transcode'; + } + else if (session.PlayState.PlayMethod === 'DirectStream') { + return 'DirectPlay'; + } + else if (session.PlayState.PlayMethod === 'DirectPlay') { + return 'DirectPlay'; + } } + return { getDisplayPlayMethod: getDisplayPlayMethod - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/playqueuemanager.js b/src/bower_components/emby-webcomponents/playback/playqueuemanager.js index 0962bfc4b0..a804af0ec5 100644 --- a/src/bower_components/emby-webcomponents/playback/playqueuemanager.js +++ b/src/bower_components/emby-webcomponents/playback/playqueuemanager.js @@ -1,103 +1,233 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; + var currentId = 0; function addUniquePlaylistItemId(item) { - item.PlaylistItemId || (item.PlaylistItemId = "playlistItem" + currentId, currentId++) + + if (!item.PlaylistItemId) { + + item.PlaylistItemId = "playlistItem" + currentId; + currentId++; + } } function findPlaylistIndex(playlistItemId, list) { - for (var i = 0, length = list.length; i < length; i++) - if (list[i].PlaylistItemId === playlistItemId) return i; - return -1 + + for (var i = 0, length = list.length; i < length; i++) { + if (list[i].PlaylistItemId === playlistItemId) { + return i; + } + } + + return -1; } function PlayQueueManager() { - this._playlist = [], this._repeatMode = "RepeatNone" + + this._playlist = []; + this._repeatMode = 'RepeatNone'; } + PlayQueueManager.prototype.getPlaylist = function () { + return this._playlist.slice(0); + }; + + PlayQueueManager.prototype.setPlaylist = function (items) { + + items = items.slice(0); + + for (var i = 0, length = items.length; i < length; i++) { + + addUniquePlaylistItemId(items[i]); + } + + this._currentPlaylistItemId = null; + this._playlist = items; + this._repeatMode = 'RepeatNone'; + }; + + PlayQueueManager.prototype.queue = function (items) { + + for (var i = 0, length = items.length; i < length; i++) { + + addUniquePlaylistItemId(items[i]); + + this._playlist.push(items[i]); + } + }; + function arrayInsertAt(destArray, pos, arrayToInsert) { var args = []; - args.push(pos), args.push(0), args = args.concat(arrayToInsert), destArray.splice.apply(destArray, args) + args.push(pos); // where to insert + args.push(0); // nothing to remove + args = args.concat(arrayToInsert); // add on array to insert + destArray.splice.apply(destArray, args); // splice it in } - function moveInArray(array, from, to) { - array.splice(to, 0, array.splice(from, 1)[0]) - } - var currentId = 0; - return PlayQueueManager.prototype.getPlaylist = function() { - return this._playlist.slice(0) - }, PlayQueueManager.prototype.setPlaylist = function(items) { - items = items.slice(0); - for (var i = 0, length = items.length; i < length; i++) addUniquePlaylistItemId(items[i]); - this._currentPlaylistItemId = null, this._playlist = items, this._repeatMode = "RepeatNone" - }, PlayQueueManager.prototype.queue = function(items) { - for (var i = 0, length = items.length; i < length; i++) addUniquePlaylistItemId(items[i]), this._playlist.push(items[i]) - }, PlayQueueManager.prototype.queueNext = function(items) { + PlayQueueManager.prototype.queueNext = function (items) { + var i, length; - for (i = 0, length = items.length; i < length; i++) addUniquePlaylistItemId(items[i]); - var currentIndex = this.getCurrentPlaylistIndex(); - 1 === currentIndex ? currentIndex = this._playlist.length : currentIndex++, arrayInsertAt(this._playlist, currentIndex, items) - }, PlayQueueManager.prototype.getCurrentPlaylistIndex = function() { - return findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist) - }, PlayQueueManager.prototype.getCurrentItem = function() { - var index = findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist); - return -1 === index ? null : this._playlist[index] - }, PlayQueueManager.prototype.getCurrentPlaylistItemId = function() { - return this._currentPlaylistItemId - }, PlayQueueManager.prototype.setPlaylistState = function(playlistItemId, playlistIndex) { - this._currentPlaylistItemId = playlistItemId - }, PlayQueueManager.prototype.setPlaylistIndex = function(playlistIndex) { - playlistIndex < 0 ? this.setPlaylistState(null) : this.setPlaylistState(this._playlist[playlistIndex].PlaylistItemId) - }, PlayQueueManager.prototype.removeFromPlaylist = function(playlistItemIds) { - var playlist = this.getPlaylist(); - if (playlist.length <= playlistItemIds.length) return { - result: "empty" - }; - var currentPlaylistItemId = this.getCurrentPlaylistItemId(), - isCurrentIndex = -1 !== playlistItemIds.indexOf(currentPlaylistItemId); - return this._playlist = playlist.filter(function(item) { - return -1 === playlistItemIds.indexOf(item.PlaylistItemId) - }), { - result: "removed", - isCurrentIndex: isCurrentIndex + + for (i = 0, length = items.length; i < length; i++) { + + addUniquePlaylistItemId(items[i]); } - }, PlayQueueManager.prototype.movePlaylistItem = function(playlistItemId, newIndex) { - for (var oldIndex, playlist = this.getPlaylist(), i = 0, length = playlist.length; i < length; i++) + + var currentIndex = this.getCurrentPlaylistIndex(); + + if (currentIndex === -1) { + currentIndex = this._playlist.length; + } else { + currentIndex++; + } + + arrayInsertAt(this._playlist, currentIndex, items); + }; + + PlayQueueManager.prototype.getCurrentPlaylistIndex = function () { + + return findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist); + }; + + PlayQueueManager.prototype.getCurrentItem = function () { + + var index = findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist); + + return index === -1 ? null : this._playlist[index]; + }; + + PlayQueueManager.prototype.getCurrentPlaylistItemId = function () { + return this._currentPlaylistItemId; + }; + + PlayQueueManager.prototype.setPlaylistState = function (playlistItemId, playlistIndex) { + + this._currentPlaylistItemId = playlistItemId; + }; + + PlayQueueManager.prototype.setPlaylistIndex = function (playlistIndex) { + + if (playlistIndex < 0) { + this.setPlaylistState(null); + } else { + this.setPlaylistState(this._playlist[playlistIndex].PlaylistItemId); + } + }; + + PlayQueueManager.prototype.removeFromPlaylist = function (playlistItemIds) { + + var playlist = this.getPlaylist(); + + if (playlist.length <= playlistItemIds.length) { + return { + result: 'empty' + }; + } + + var currentPlaylistItemId = this.getCurrentPlaylistItemId(); + var isCurrentIndex = playlistItemIds.indexOf(currentPlaylistItemId) !== -1; + + this._playlist = playlist.filter(function (item) { + return playlistItemIds.indexOf(item.PlaylistItemId) === -1; + }); + + return { + result: 'removed', + isCurrentIndex: isCurrentIndex + }; + }; + + function moveInArray(array, from, to) { + array.splice(to, 0, array.splice(from, 1)[0]); + } + + PlayQueueManager.prototype.movePlaylistItem = function (playlistItemId, newIndex) { + + var playlist = this.getPlaylist(); + + var oldIndex; + for (var i = 0, length = playlist.length; i < length; i++) { if (playlist[i].PlaylistItemId === playlistItemId) { oldIndex = i; - break - } if (-1 === oldIndex || oldIndex === newIndex) return { - result: "noop" - }; - if (newIndex >= playlist.length) throw new Error("newIndex out of bounds"); - return moveInArray(playlist, oldIndex, newIndex), this._playlist = playlist, { - result: "moved", + break; + } + } + + if (oldIndex === -1 || oldIndex === newIndex) { + return { + result: 'noop' + }; + } + + if (newIndex >= playlist.length) { + throw new Error('newIndex out of bounds'); + } + + moveInArray(playlist, oldIndex, newIndex); + + this._playlist = playlist; + + return { + result: 'moved', playlistItemId: playlistItemId, newIndex: newIndex - } - }, PlayQueueManager.prototype.reset = function() { - this._playlist = [], this._currentPlaylistItemId = null, this._repeatMode = "RepeatNone" - }, PlayQueueManager.prototype.setRepeatMode = function(value) { - this._repeatMode = value - }, PlayQueueManager.prototype.getRepeatMode = function() { - return this._repeatMode - }, PlayQueueManager.prototype.getNextItemInfo = function() { - var newIndex, playlist = this.getPlaylist(), - playlistLength = playlist.length; + }; + }; + + PlayQueueManager.prototype.reset = function () { + + this._playlist = []; + this._currentPlaylistItemId = null; + this._repeatMode = 'RepeatNone'; + }; + + PlayQueueManager.prototype.setRepeatMode = function (value) { + + this._repeatMode = value; + }; + + PlayQueueManager.prototype.getRepeatMode = function () { + + return this._repeatMode; + }; + + PlayQueueManager.prototype.getNextItemInfo = function () { + + var newIndex; + var playlist = this.getPlaylist(); + var playlistLength = playlist.length; + switch (this.getRepeatMode()) { - case "RepeatOne": + + case 'RepeatOne': newIndex = this.getCurrentPlaylistIndex(); break; - case "RepeatAll": - newIndex = this.getCurrentPlaylistIndex() + 1, newIndex >= playlistLength && (newIndex = 0); + case 'RepeatAll': + newIndex = this.getCurrentPlaylistIndex() + 1; + if (newIndex >= playlistLength) { + newIndex = 0; + } break; default: - newIndex = this.getCurrentPlaylistIndex() + 1 + newIndex = this.getCurrentPlaylistIndex() + 1; + break; } - if (newIndex < 0 || newIndex >= playlistLength) return null; + + if (newIndex < 0 || newIndex >= playlistLength) { + return null; + } + var item = playlist[newIndex]; - return item ? { + + if (!item) { + return null; + } + + return { item: item, index: newIndex - } : null - }, PlayQueueManager + }; + }; + + return PlayQueueManager; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/remotecontrolautoplay.js b/src/bower_components/emby-webcomponents/playback/remotecontrolautoplay.js index 6cc1929497..5fecf48537 100644 --- a/src/bower_components/emby-webcomponents/playback/remotecontrolautoplay.js +++ b/src/bower_components/emby-webcomponents/playback/remotecontrolautoplay.js @@ -1,22 +1,47 @@ -define(["events", "playbackManager"], function(events, playbackManager) { - "use strict"; +define(['events', 'playbackManager'], function (events, playbackManager) { + 'use strict'; function transferPlayback(oldPlayer, newPlayer) { - var state = playbackManager.getPlayerState(oldPlayer), - item = state.NowPlayingItem; - if (item) { - var playState = state.PlayState || {}, - resumePositionTicks = playState.PositionTicks || 0; - playbackManager.stop(oldPlayer).then(function() { - playbackManager.play({ - ids: [item.Id], - serverId: item.ServerId, - startPositionTicks: resumePositionTicks - }, newPlayer) - }) + + var state = playbackManager.getPlayerState(oldPlayer); + + var item = state.NowPlayingItem; + + if (!item) { + return; } + + var playState = state.PlayState || {}; + var resumePositionTicks = playState.PositionTicks || 0; + + playbackManager.stop(oldPlayer).then(function () { + + playbackManager.play({ + ids: [item.Id], + serverId: item.ServerId, + startPositionTicks: resumePositionTicks + + }, newPlayer); + }); } - events.on(playbackManager, "playerchange", function(e, newPlayer, newTarget, oldPlayer) { - if (oldPlayer && newPlayer) return oldPlayer.isLocalPlayer ? newPlayer.isLocalPlayer ? void console.log("Skipping remote control autoplay because newPlayer is a local player") : void transferPlayback(oldPlayer, newPlayer) : void console.log("Skipping remote control autoplay because oldPlayer is not a local player") - }) + + events.on(playbackManager, 'playerchange', function (e, newPlayer, newTarget, oldPlayer) { + + if (!oldPlayer || !newPlayer) { + return; + } + + if (!oldPlayer.isLocalPlayer) { + console.log('Skipping remote control autoplay because oldPlayer is not a local player'); + return; + } + + if (newPlayer.isLocalPlayer) { + console.log('Skipping remote control autoplay because newPlayer is a local player'); + return; + } + + transferPlayback(oldPlayer, newPlayer); + }); + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playback/volumeosd.js b/src/bower_components/emby-webcomponents/playback/volumeosd.js index 0987947f6f..c967a34fe2 100644 --- a/src/bower_components/emby-webcomponents/playback/volumeosd.js +++ b/src/bower_components/emby-webcomponents/playback/volumeosd.js @@ -1,63 +1,158 @@ -define(["events", "playbackManager", "dom", "browser", "css!./iconosd", "material-icons"], function(events, playbackManager, dom, browser) { - "use strict"; +define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'material-icons'], function (events, playbackManager, dom, browser) { + 'use strict'; + + var currentPlayer; + var osdElement; + var iconElement; + var progressElement; + + var enableAnimation; function getOsdElementHtml() { - var html = ""; - return html += '', html += '
' + var html = ''; + + html += ''; + + html += '
'; + + return html; } function ensureOsdElement() { + var elem = osdElement; - elem || (enableAnimation = browser.supportsCssAnimation(), elem = document.createElement("div"), elem.classList.add("hide"), elem.classList.add("iconOsd"), elem.classList.add("iconOsd-hidden"), elem.classList.add("volumeOsd"), elem.innerHTML = getOsdElementHtml(), iconElement = elem.querySelector("i"), progressElement = elem.querySelector(".iconOsdProgressInner"), document.body.appendChild(elem), osdElement = elem) + if (!elem) { + + enableAnimation = browser.supportsCssAnimation(); + + elem = document.createElement('div'); + elem.classList.add('hide'); + elem.classList.add('iconOsd'); + elem.classList.add('iconOsd-hidden'); + elem.classList.add('volumeOsd'); + elem.innerHTML = getOsdElementHtml(); + + iconElement = elem.querySelector('i'); + progressElement = elem.querySelector('.iconOsdProgressInner'); + + document.body.appendChild(elem); + osdElement = elem; + } } function onHideComplete() { - this.classList.add("hide") + this.classList.add('hide'); } + var hideTimeout; function showOsd() { + clearHideTimeout(); + var elem = osdElement; + dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { - once: !0 - }), elem.classList.remove("hide"), elem.offsetWidth, requestAnimationFrame(function() { - elem.classList.remove("iconOsd-hidden"), hideTimeout = setTimeout(hideOsd, 3e3) - }) + once: true + }); + + elem.classList.remove('hide'); + + // trigger reflow + void elem.offsetWidth; + + requestAnimationFrame(function () { + elem.classList.remove('iconOsd-hidden'); + + hideTimeout = setTimeout(hideOsd, 3000); + }); } function clearHideTimeout() { - hideTimeout && (clearTimeout(hideTimeout), hideTimeout = null) + if (hideTimeout) { + clearTimeout(hideTimeout); + hideTimeout = null; + } } function hideOsd() { + clearHideTimeout(); + var elem = osdElement; - elem && (enableAnimation ? (elem.offsetWidth, requestAnimationFrame(function() { - elem.classList.add("iconOsd-hidden"), dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { - once: !0 - }) - })) : onHideComplete.call(elem)) + if (elem) { + + if (enableAnimation) { + // trigger reflow + void elem.offsetWidth; + + requestAnimationFrame(function () { + elem.classList.add('iconOsd-hidden'); + + dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { + once: true + }); + }); + } else { + onHideComplete.call(elem); + } + } } function updatePlayerVolumeState(isMuted, volume) { - iconElement && (iconElement.innerHTML = isMuted ? "" : ""), progressElement && (progressElement.style.width = (volume || 0) + "%") + + if (iconElement) { + iconElement.innerHTML = isMuted ? '' : ''; + } + if (progressElement) { + progressElement.style.width = (volume || 0) + '%'; + } } function releaseCurrentPlayer() { + var player = currentPlayer; - player && (events.off(player, "volumechange", onVolumeChanged), events.off(player, "playbackstop", hideOsd), currentPlayer = null) + + if (player) { + events.off(player, 'volumechange', onVolumeChanged); + events.off(player, 'playbackstop', hideOsd); + currentPlayer = null; + } } function onVolumeChanged(e) { + var player = this; - ensureOsdElement(), updatePlayerVolumeState(player.isMuted(), player.getVolume()), showOsd() + + ensureOsdElement(); + + updatePlayerVolumeState(player.isMuted(), player.getVolume()); + + showOsd(); } function bindToPlayer(player) { - player !== currentPlayer && (releaseCurrentPlayer(), currentPlayer = player, player && (hideOsd(), events.on(player, "volumechange", onVolumeChanged), events.on(player, "playbackstop", hideOsd))) + + if (player === currentPlayer) { + return; + } + + releaseCurrentPlayer(); + + currentPlayer = player; + + if (!player) { + return; + } + + hideOsd(); + events.on(player, 'volumechange', onVolumeChanged); + events.on(player, 'playbackstop', hideOsd); } - var currentPlayer, osdElement, iconElement, progressElement, enableAnimation, hideTimeout; - events.on(playbackManager, "playerchange", function() { - bindToPlayer(playbackManager.getCurrentPlayer()) - }), bindToPlayer(playbackManager.getCurrentPlayer()) + + events.on(playbackManager, 'playerchange', function () { + bindToPlayer(playbackManager.getCurrentPlayer()); + }); + + bindToPlayer(playbackManager.getCurrentPlayer()); + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playbacksettings/playbacksettings.js b/src/bower_components/emby-webcomponents/playbacksettings/playbacksettings.js index bb74207382..6e0cb5e30f 100644 --- a/src/bower_components/emby-webcomponents/playbacksettings/playbacksettings.js +++ b/src/bower_components/emby-webcomponents/playbacksettings/playbacksettings.js @@ -1,135 +1,345 @@ -define(["require", "browser", "appSettings", "apphost", "focusManager", "qualityoptions", "globalize", "loading", "connectionManager", "dom", "events", "emby-select", "emby-checkbox"], function(require, browser, appSettings, appHost, focusManager, qualityoptions, globalize, loading, connectionManager, dom, events) { +define(['require', 'browser', 'appSettings', 'apphost', 'focusManager', 'qualityoptions', 'globalize', 'loading', 'connectionManager', 'dom', 'events', 'emby-select', 'emby-checkbox'], function (require, browser, appSettings, appHost, focusManager, qualityoptions, globalize, loading, connectionManager, dom, events) { "use strict"; function fillSkipLengths(select) { + var options = [5, 10, 15, 20, 25, 30]; - select.innerHTML = options.map(function(option) { + + select.innerHTML = options.map(function (option) { return { - name: globalize.translate("sharedcomponents#ValueSeconds", option), - value: 1e3 * option - } - }).map(function(o) { - return '" - }).join("") + name: globalize.translate('sharedcomponents#ValueSeconds', option), + value: option * 1000 + }; + }).map(function (o) { + return ''; + }).join(''); } function populateLanguages(select, languages) { + var html = ""; - html += ""; + + html += ""; + for (var i = 0, length = languages.length; i < length; i++) { + var culture = languages[i]; - html += "" + + html += ""; } - select.innerHTML = html + + select.innerHTML = html; } function setMaxBitrateIntoField(select, isInNetwork, mediatype) { - var options = "Audio" === mediatype ? qualityoptions.getAudioQualityOptions({ + + var options = mediatype === 'Audio' ? qualityoptions.getAudioQualityOptions({ + currentMaxBitrate: appSettings.maxStreamingBitrate(isInNetwork, mediatype), isAutomaticBitrateEnabled: appSettings.enableAutomaticBitrateDetection(isInNetwork, mediatype), - enableAuto: !0 + enableAuto: true + }) : qualityoptions.getVideoQualityOptions({ + currentMaxBitrate: appSettings.maxStreamingBitrate(isInNetwork, mediatype), isAutomaticBitrateEnabled: appSettings.enableAutomaticBitrateDetection(isInNetwork, mediatype), - enableAuto: !0 + enableAuto: true + }); - select.innerHTML = options.map(function(i) { - return '" - }).join(""), appSettings.enableAutomaticBitrateDetection(isInNetwork, mediatype) ? select.value = "" : select.value = appSettings.maxStreamingBitrate(isInNetwork, mediatype) + + select.innerHTML = options.map(function (i) { + + // render empty string instead of 0 for the auto option + return ''; + }).join(''); + + if (appSettings.enableAutomaticBitrateDetection(isInNetwork, mediatype)) { + select.value = ''; + } else { + select.value = appSettings.maxStreamingBitrate(isInNetwork, mediatype); + } } function fillChromecastQuality(select) { + var options = qualityoptions.getVideoQualityOptions({ + currentMaxBitrate: appSettings.maxChromecastBitrate(), isAutomaticBitrateEnabled: !appSettings.maxChromecastBitrate(), - enableAuto: !0 + enableAuto: true }); - select.innerHTML = options.map(function(i) { - return '" - }).join(""), select.value = appSettings.maxChromecastBitrate() || "" + + select.innerHTML = options.map(function (i) { + + // render empty string instead of 0 for the auto option + return ''; + }).join(''); + + select.value = appSettings.maxChromecastBitrate() || ''; } function setMaxBitrateFromField(select, isInNetwork, mediatype, value) { - select.value ? (appSettings.maxStreamingBitrate(isInNetwork, mediatype, select.value), appSettings.enableAutomaticBitrateDetection(isInNetwork, mediatype, !1)) : appSettings.enableAutomaticBitrateDetection(isInNetwork, mediatype, !0) + + if (select.value) { + appSettings.maxStreamingBitrate(isInNetwork, mediatype, select.value); + appSettings.enableAutomaticBitrateDetection(isInNetwork, mediatype, false); + } else { + appSettings.enableAutomaticBitrateDetection(isInNetwork, mediatype, true); + } } function showHideQualityFields(context, user, apiClient) { - if (user.Policy.EnableVideoPlaybackTranscoding ? context.querySelector(".videoQualitySection").classList.remove("hide") : context.querySelector(".videoQualitySection").classList.add("hide"), appHost.supports("multiserver")) return context.querySelector(".fldVideoInNetworkQuality").classList.remove("hide"), context.querySelector(".fldVideoInternetQuality").classList.remove("hide"), void(user.Policy.EnableAudioPlaybackTranscoding ? context.querySelector(".musicQualitySection").classList.remove("hide") : context.querySelector(".musicQualitySection").classList.add("hide")); - apiClient.getEndpointInfo().then(function(endpointInfo) { - endpointInfo.IsInNetwork ? (context.querySelector(".fldVideoInNetworkQuality").classList.remove("hide"), context.querySelector(".fldVideoInternetQuality").classList.add("hide"), context.querySelector(".musicQualitySection").classList.add("hide")) : (context.querySelector(".fldVideoInNetworkQuality").classList.add("hide"), context.querySelector(".fldVideoInternetQuality").classList.remove("hide"), user.Policy.EnableAudioPlaybackTranscoding ? context.querySelector(".musicQualitySection").classList.remove("hide") : context.querySelector(".musicQualitySection").classList.add("hide")) - }) + + if (user.Policy.EnableVideoPlaybackTranscoding) { + context.querySelector('.videoQualitySection').classList.remove('hide'); + } else { + context.querySelector('.videoQualitySection').classList.add('hide'); + } + + if (appHost.supports('multiserver')) { + + context.querySelector('.fldVideoInNetworkQuality').classList.remove('hide'); + context.querySelector('.fldVideoInternetQuality').classList.remove('hide'); + + if (user.Policy.EnableAudioPlaybackTranscoding) { + context.querySelector('.musicQualitySection').classList.remove('hide'); + } else { + context.querySelector('.musicQualitySection').classList.add('hide'); + } + + return; + } + + apiClient.getEndpointInfo().then(function (endpointInfo) { + + if (endpointInfo.IsInNetwork) { + + context.querySelector('.fldVideoInNetworkQuality').classList.remove('hide'); + + context.querySelector('.fldVideoInternetQuality').classList.add('hide'); + context.querySelector('.musicQualitySection').classList.add('hide'); + } else { + + context.querySelector('.fldVideoInNetworkQuality').classList.add('hide'); + + context.querySelector('.fldVideoInternetQuality').classList.remove('hide'); + + if (user.Policy.EnableAudioPlaybackTranscoding) { + context.querySelector('.musicQualitySection').classList.remove('hide'); + } else { + context.querySelector('.musicQualitySection').classList.add('hide'); + } + } + }); } function showOrHideEpisodesField(context, user, apiClient) { - if (browser.tizen || browser.web0s) return void context.querySelector(".fldEpisodeAutoPlay").classList.add("hide"); - context.querySelector(".fldEpisodeAutoPlay").classList.remove("hide") + + if (browser.tizen || browser.web0s) { + context.querySelector('.fldEpisodeAutoPlay').classList.add('hide'); + return; + } + + context.querySelector('.fldEpisodeAutoPlay').classList.remove('hide'); } function loadForm(context, user, userSettings, apiClient) { - var loggedInUserId = apiClient.getCurrentUserId(), - userId = user.Id; - showHideQualityFields(context, user, apiClient), apiClient.getCultures().then(function(allCultures) { - populateLanguages(context.querySelector("#selectAudioLanguage"), allCultures), context.querySelector("#selectAudioLanguage", context).value = user.Configuration.AudioLanguagePreference || "", context.querySelector(".chkEpisodeAutoPlay").checked = user.Configuration.EnableNextEpisodeAutoPlay || !1 - }), apiClient.getNamedConfiguration("cinemamode").then(function(cinemaConfig) { - cinemaConfig.EnableIntrosForMovies || cinemaConfig.EnableIntrosForEpisodes ? context.querySelector(".cinemaModeOptions").classList.remove("hide") : context.querySelector(".cinemaModeOptions").classList.add("hide") - }), appHost.supports("externalplayerintent") && userId === loggedInUserId ? context.querySelector(".fldExternalPlayer").classList.remove("hide") : context.querySelector(".fldExternalPlayer").classList.add("hide"), userId === loggedInUserId && (user.Policy.EnableVideoPlaybackTranscoding || user.Policy.EnableAudioPlaybackTranscoding) ? (context.querySelector(".qualitySections").classList.remove("hide"), appHost.supports("chromecast") && user.Policy.EnableVideoPlaybackTranscoding ? context.querySelector(".fldChromecastQuality").classList.remove("hide") : context.querySelector(".fldChromecastQuality").classList.add("hide")) : (context.querySelector(".qualitySections").classList.add("hide"), context.querySelector(".fldChromecastQuality").classList.add("hide")), browser.tizen || browser.web0s ? context.querySelector(".fldEnableNextVideoOverlay").classList.add("hide") : context.querySelector(".fldEnableNextVideoOverlay").classList.remove("hide"), context.querySelector(".chkPlayDefaultAudioTrack").checked = user.Configuration.PlayDefaultAudioTrack || !1, context.querySelector(".chkEnableCinemaMode").checked = userSettings.enableCinemaMode(), context.querySelector(".chkEnableNextVideoOverlay").checked = userSettings.enableNextVideoInfoOverlay(), context.querySelector(".chkExternalVideoPlayer").checked = appSettings.enableSystemExternalPlayers(), setMaxBitrateIntoField(context.querySelector(".selectVideoInNetworkQuality"), !0, "Video"), setMaxBitrateIntoField(context.querySelector(".selectVideoInternetQuality"), !1, "Video"), setMaxBitrateIntoField(context.querySelector(".selectMusicInternetQuality"), !1, "Audio"), fillChromecastQuality(context.querySelector(".selectChromecastVideoQuality")); - var selectSkipForwardLength = context.querySelector(".selectSkipForwardLength"); - fillSkipLengths(selectSkipForwardLength), selectSkipForwardLength.value = userSettings.skipForwardLength(); - var selectSkipBackLength = context.querySelector(".selectSkipBackLength"); - fillSkipLengths(selectSkipBackLength), selectSkipBackLength.value = userSettings.skipBackLength(), showOrHideEpisodesField(context, user, apiClient), loading.hide() + + var loggedInUserId = apiClient.getCurrentUserId(); + var userId = user.Id; + + showHideQualityFields(context, user, apiClient); + + apiClient.getCultures().then(function (allCultures) { + + populateLanguages(context.querySelector('#selectAudioLanguage'), allCultures); + + context.querySelector('#selectAudioLanguage', context).value = user.Configuration.AudioLanguagePreference || ""; + context.querySelector('.chkEpisodeAutoPlay').checked = user.Configuration.EnableNextEpisodeAutoPlay || false; + }); + + // hide cinema mode options if disabled at server level + apiClient.getNamedConfiguration("cinemamode").then(function (cinemaConfig) { + + if (cinemaConfig.EnableIntrosForMovies || cinemaConfig.EnableIntrosForEpisodes) { + context.querySelector('.cinemaModeOptions').classList.remove('hide'); + } else { + context.querySelector('.cinemaModeOptions').classList.add('hide'); + } + }); + + if (appHost.supports('externalplayerintent') && userId === loggedInUserId) { + context.querySelector('.fldExternalPlayer').classList.remove('hide'); + } else { + context.querySelector('.fldExternalPlayer').classList.add('hide'); + } + + if (userId === loggedInUserId && (user.Policy.EnableVideoPlaybackTranscoding || user.Policy.EnableAudioPlaybackTranscoding)) { + context.querySelector('.qualitySections').classList.remove('hide'); + + if (appHost.supports('chromecast') && user.Policy.EnableVideoPlaybackTranscoding) { + context.querySelector('.fldChromecastQuality').classList.remove('hide'); + } else { + context.querySelector('.fldChromecastQuality').classList.add('hide'); + } + } else { + context.querySelector('.qualitySections').classList.add('hide'); + context.querySelector('.fldChromecastQuality').classList.add('hide'); + } + + if (browser.tizen || browser.web0s) { + context.querySelector('.fldEnableNextVideoOverlay').classList.add('hide'); + } else { + context.querySelector('.fldEnableNextVideoOverlay').classList.remove('hide'); + } + + context.querySelector('.chkPlayDefaultAudioTrack').checked = user.Configuration.PlayDefaultAudioTrack || false; + context.querySelector('.chkEnableCinemaMode').checked = userSettings.enableCinemaMode(); + context.querySelector('.chkEnableNextVideoOverlay').checked = userSettings.enableNextVideoInfoOverlay(); + context.querySelector('.chkExternalVideoPlayer').checked = appSettings.enableSystemExternalPlayers(); + + setMaxBitrateIntoField(context.querySelector('.selectVideoInNetworkQuality'), true, 'Video'); + setMaxBitrateIntoField(context.querySelector('.selectVideoInternetQuality'), false, 'Video'); + setMaxBitrateIntoField(context.querySelector('.selectMusicInternetQuality'), false, 'Audio'); + + fillChromecastQuality(context.querySelector('.selectChromecastVideoQuality')); + + var selectSkipForwardLength = context.querySelector('.selectSkipForwardLength'); + fillSkipLengths(selectSkipForwardLength); + selectSkipForwardLength.value = userSettings.skipForwardLength(); + + var selectSkipBackLength = context.querySelector('.selectSkipBackLength'); + fillSkipLengths(selectSkipBackLength); + selectSkipBackLength.value = userSettings.skipBackLength(); + + showOrHideEpisodesField(context, user, apiClient); + + loading.hide(); } function saveUser(context, user, userSettingsInstance, apiClient) { - return appSettings.enableSystemExternalPlayers(context.querySelector(".chkExternalVideoPlayer").checked), appSettings.maxChromecastBitrate(context.querySelector(".selectChromecastVideoQuality").value), setMaxBitrateFromField(context.querySelector(".selectVideoInNetworkQuality"), !0, "Video"), setMaxBitrateFromField(context.querySelector(".selectVideoInternetQuality"), !1, "Video"), setMaxBitrateFromField(context.querySelector(".selectMusicInternetQuality"), !1, "Audio"), user.Configuration.AudioLanguagePreference = context.querySelector("#selectAudioLanguage").value, user.Configuration.PlayDefaultAudioTrack = context.querySelector(".chkPlayDefaultAudioTrack").checked, user.Configuration.EnableNextEpisodeAutoPlay = context.querySelector(".chkEpisodeAutoPlay").checked, userSettingsInstance.enableCinemaMode(context.querySelector(".chkEnableCinemaMode").checked), userSettingsInstance.enableNextVideoInfoOverlay(context.querySelector(".chkEnableNextVideoOverlay").checked), userSettingsInstance.skipForwardLength(context.querySelector(".selectSkipForwardLength").value), userSettingsInstance.skipBackLength(context.querySelector(".selectSkipBackLength").value), apiClient.updateUserConfiguration(user.Id, user.Configuration) + + appSettings.enableSystemExternalPlayers(context.querySelector('.chkExternalVideoPlayer').checked); + + appSettings.maxChromecastBitrate(context.querySelector('.selectChromecastVideoQuality').value); + + setMaxBitrateFromField(context.querySelector('.selectVideoInNetworkQuality'), true, 'Video'); + setMaxBitrateFromField(context.querySelector('.selectVideoInternetQuality'), false, 'Video'); + setMaxBitrateFromField(context.querySelector('.selectMusicInternetQuality'), false, 'Audio'); + + user.Configuration.AudioLanguagePreference = context.querySelector('#selectAudioLanguage').value; + user.Configuration.PlayDefaultAudioTrack = context.querySelector('.chkPlayDefaultAudioTrack').checked; + user.Configuration.EnableNextEpisodeAutoPlay = context.querySelector('.chkEpisodeAutoPlay').checked; + + userSettingsInstance.enableCinemaMode(context.querySelector('.chkEnableCinemaMode').checked); + + userSettingsInstance.enableNextVideoInfoOverlay(context.querySelector('.chkEnableNextVideoOverlay').checked); + userSettingsInstance.skipForwardLength(context.querySelector('.selectSkipForwardLength').value); + userSettingsInstance.skipBackLength(context.querySelector('.selectSkipBackLength').value); + + return apiClient.updateUserConfiguration(user.Id, user.Configuration); } function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) { - loading.show(), apiClient.getUser(userId).then(function(user) { - saveUser(context, user, userSettings, apiClient).then(function() { - loading.hide(), enableSaveConfirmation && require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#SettingsSaved")) - }), events.trigger(instance, "saved") - }, function() { - loading.hide() - }) - }) + + loading.show(); + + apiClient.getUser(userId).then(function (user) { + + saveUser(context, user, userSettings, apiClient).then(function () { + + loading.hide(); + if (enableSaveConfirmation) { + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#SettingsSaved')); + }); + } + + events.trigger(instance, 'saved'); + + }, function () { + loading.hide(); + }); + }); } function onSubmit(e) { - var self = this, - apiClient = connectionManager.getApiClient(self.options.serverId), - userId = self.options.userId, - userSettings = self.options.userSettings; - return userSettings.setUserInfo(userId, apiClient).then(function() { + + var self = this; + var apiClient = connectionManager.getApiClient(self.options.serverId); + var userId = self.options.userId; + var userSettings = self.options.userSettings; + + userSettings.setUserInfo(userId, apiClient).then(function () { + var enableSaveConfirmation = self.options.enableSaveConfirmation; - save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation) - }), e && e.preventDefault(), !1 + save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation); + }); + + // Disable default form submission + if (e) { + e.preventDefault(); + } + return false; } function embed(options, self) { - require(["text!./playbacksettings.template.html"], function(template) { - options.element.innerHTML = globalize.translateDocument(template, "sharedcomponents"), options.element.querySelector("form").addEventListener("submit", onSubmit.bind(self)), options.enableSaveButton && options.element.querySelector(".btnSave").classList.remove("hide"), self.loadData(), options.autoFocus && focusManager.autoFocus(options.element) - }) + + require(['text!./playbacksettings.template.html'], function (template) { + + options.element.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self)); + + if (options.enableSaveButton) { + options.element.querySelector('.btnSave').classList.remove('hide'); + } + + self.loadData(); + + if (options.autoFocus) { + focusManager.autoFocus(options.element); + } + }); } function PlaybackSettings(options) { - this.options = options, embed(options, this) + + this.options = options; + + embed(options, this); } - return PlaybackSettings.prototype.loadData = function() { - var self = this, - context = self.options.element; + + PlaybackSettings.prototype.loadData = function () { + + var self = this; + var context = self.options.element; + loading.show(); - var userId = self.options.userId, - apiClient = connectionManager.getApiClient(self.options.serverId), - userSettings = self.options.userSettings; - apiClient.getUser(userId).then(function(user) { - userSettings.setUserInfo(userId, apiClient).then(function() { - self.dataLoaded = !0, loadForm(context, user, userSettings, apiClient) - }) - }) - }, PlaybackSettings.prototype.submit = function() { - onSubmit.call(this) - }, PlaybackSettings.prototype.destroy = function() { - this.options = null - }, PlaybackSettings + + var userId = self.options.userId; + var apiClient = connectionManager.getApiClient(self.options.serverId); + var userSettings = self.options.userSettings; + + apiClient.getUser(userId).then(function (user) { + + userSettings.setUserInfo(userId, apiClient).then(function () { + + self.dataLoaded = true; + + loadForm(context, user, userSettings, apiClient); + }); + }); + }; + + PlaybackSettings.prototype.submit = function () { + onSubmit.call(this); + }; + + PlaybackSettings.prototype.destroy = function () { + + this.options = null; + }; + + return PlaybackSettings; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playerstats/playerstats.css b/src/bower_components/emby-webcomponents/playerstats/playerstats.css index 865200c767..b9d6355bd2 100644 --- a/src/bower_components/emby-webcomponents/playerstats/playerstats.css +++ b/src/bower_components/emby-webcomponents/playerstats/playerstats.css @@ -1,24 +1,24 @@ .playerStats { - background: rgba(28, 28, 28, .8); - -webkit-border-radius: .3em; + background: rgba(28,28,28,0.8); border-radius: .3em; + color: #fff; left: 1.5em; position: absolute; top: 5em; - color: #fff + color: #fff; } .playerStats-tv { - top: 4em + top: 4em; } .playerStats-content { position: relative; - font-size: 84% + font-size: 84%; } .playerStats-content-tv { - font-size: 60% + font-size: 60%; } .playerStats-closeButton { @@ -26,38 +26,31 @@ top: .25em; right: .25em; color: #ccc; - z-index: 1 + z-index: 1; } .playerStats-stats { - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; flex-direction: column; padding: 0 3em 1em 1em; max-width: 50em; - overflow: hidden + overflow: hidden; } .playerStats-stat { - display: -webkit-box; - display: -webkit-flex; display: flex; - margin-left: 1em + margin-left: 1em; } .playerStats-stat-label { font-weight: 500; - margin: 0 .5em 0 0 + margin: 0 .5em 0 0; } .playerStats-stat-header { - margin: 1em 1em 0 0 + margin: 1em 1em 0 0; } .playerStats-stat-value { - color: #ddd -} \ No newline at end of file + color: #ddd; +} diff --git a/src/bower_components/emby-webcomponents/playerstats/playerstats.js b/src/bower_components/emby-webcomponents/playerstats/playerstats.js index a089690aa0..f0cca7c804 100644 --- a/src/bower_components/emby-webcomponents/playerstats/playerstats.js +++ b/src/bower_components/emby-webcomponents/playerstats/playerstats.js @@ -1,193 +1,466 @@ -define(["events", "globalize", "playbackManager", "connectionManager", "playMethodHelper", "layoutManager", "serverNotifications", "paper-icon-button-light", "css!./playerstats"], function(events, globalize, playbackManager, connectionManager, playMethodHelper, layoutManager, serverNotifications) { - "use strict"; +define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMethodHelper', 'layoutManager', 'serverNotifications', 'paper-icon-button-light', 'css!./playerstats'], function (events, globalize, playbackManager, connectionManager, playMethodHelper, layoutManager, serverNotifications) { + 'use strict'; function init(instance) { - var parent = document.createElement("div"); - parent.classList.add("playerStats"), layoutManager.tv && parent.classList.add("playerStats-tv"), parent.classList.add("hide"); + + var parent = document.createElement('div'); + + parent.classList.add('playerStats'); + + if (layoutManager.tv) { + parent.classList.add('playerStats-tv'); + } + + parent.classList.add('hide'); + var button; - button = layoutManager.tv ? "" : ''; - var contentClass = layoutManager.tv ? "playerStats-content playerStats-content-tv" : "playerStats-content"; - parent.innerHTML = '
' + button + '
', button = parent.querySelector(".playerStats-closeButton"), button && button.addEventListener("click", onCloseButtonClick.bind(instance)), document.body.appendChild(parent), instance.element = parent + + if (layoutManager.tv) { + button = ''; + } else { + button = ''; + } + + var contentClass = layoutManager.tv ? 'playerStats-content playerStats-content-tv' : 'playerStats-content'; + + parent.innerHTML = '
' + button + '
'; + + button = parent.querySelector('.playerStats-closeButton'); + + if (button) { + button.addEventListener('click', onCloseButtonClick.bind(instance)); + } + + document.body.appendChild(parent); + + instance.element = parent; } function onCloseButtonClick() { - this.enabled(!1) + this.enabled(false); } function renderStats(elem, categories) { - elem.querySelector(".playerStats-stats").innerHTML = categories.map(function(category) { - var categoryHtml = "", - stats = category.stats; - stats.length && category.name && (categoryHtml += '
', categoryHtml += '
', categoryHtml += category.name, categoryHtml += "
", categoryHtml += '
', categoryHtml += category.subText || "", categoryHtml += "
", categoryHtml += "
"); - for (var i = 0, length = stats.length; i < length; i++) { - categoryHtml += '
'; - var stat = stats[i]; - categoryHtml += '
', categoryHtml += stat.label, categoryHtml += "
", categoryHtml += '
', categoryHtml += stat.value, categoryHtml += "
", categoryHtml += "
" + + elem.querySelector('.playerStats-stats').innerHTML = categories.map(function (category) { + + var categoryHtml = ''; + + var stats = category.stats; + + if (stats.length && category.name) { + categoryHtml += '
'; + + categoryHtml += '
'; + categoryHtml += category.name; + categoryHtml += '
'; + + categoryHtml += '
'; + categoryHtml += category.subText || ''; + categoryHtml += '
'; + + categoryHtml += '
'; } - return categoryHtml - }).join("") + + for (var i = 0, length = stats.length; i < length; i++) { + + categoryHtml += '
'; + + var stat = stats[i]; + + categoryHtml += '
'; + categoryHtml += stat.label; + categoryHtml += '
'; + + categoryHtml += '
'; + categoryHtml += stat.value; + categoryHtml += '
'; + + categoryHtml += '
'; + } + + return categoryHtml; + + }).join(''); } function getSession(instance, player) { - if ((new Date).getTime() - (instance.lastSessionTime || 0) < 1e4) return Promise.resolve(instance.lastSession); + + var now = new Date().getTime(); + + if ((now - (instance.lastSessionTime || 0)) < 10000) { + return Promise.resolve(instance.lastSession); + } + var apiClient = connectionManager.getApiClient(playbackManager.currentItem(player).ServerId); + return apiClient.getSessions({ deviceId: apiClient.deviceId() - }).then(function(sessions) { - return instance.lastSession = sessions[0] || {}, instance.lastSessionTime = (new Date).getTime(), Promise.resolve(instance.lastSession) - }, function() { - return Promise.resolve({}) - }) + }).then(function (sessions) { + + instance.lastSession = sessions[0] || {}; + instance.lastSessionTime = new Date().getTime(); + + return Promise.resolve(instance.lastSession); + + }, function () { + return Promise.resolve({}); + }); } function translateReason(reason) { - return globalize.translate("sharedcomponents#" + reason) + + return globalize.translate('sharedcomponents#' + reason); } function getTranscodingStats(session, player, displayPlayMethod) { - var videoCodec, audioCodec, totalBitrate, sessionStats = []; - return session.TranscodingInfo && (videoCodec = session.TranscodingInfo.VideoCodec, audioCodec = session.TranscodingInfo.AudioCodec, totalBitrate = session.TranscodingInfo.Bitrate, session.TranscodingInfo.AudioChannels), videoCodec && sessionStats.push({ - label: "Video codec:", - value: session.TranscodingInfo.IsVideoDirect ? videoCodec.toUpperCase() + " (direct)" : videoCodec.toUpperCase() - }), audioCodec && sessionStats.push({ - label: "Audio codec:", - value: session.TranscodingInfo.IsAudioDirect ? audioCodec.toUpperCase() + " (direct)" : audioCodec.toUpperCase() - }), "Transcode" === displayPlayMethod && (totalBitrate && sessionStats.push({ - label: "Bitrate:", - value: getDisplayBitrate(totalBitrate) - }), session.TranscodingInfo.CompletionPercentage && sessionStats.push({ - label: "Transcoding progress:", - value: session.TranscodingInfo.CompletionPercentage.toFixed(1) + "%" - }), session.TranscodingInfo.Framerate && sessionStats.push({ - label: "Transcoding framerate:", - value: session.TranscodingInfo.Framerate + " fps" - }), session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length && sessionStats.push({ - label: "Reason for transcoding:", - value: session.TranscodingInfo.TranscodeReasons.map(translateReason).join("
") - })), sessionStats + var sessionStats = []; + + var videoCodec; + var audioCodec; + var totalBitrate; + var audioChannels; + + if (session.TranscodingInfo) { + + videoCodec = session.TranscodingInfo.VideoCodec; + audioCodec = session.TranscodingInfo.AudioCodec; + totalBitrate = session.TranscodingInfo.Bitrate; + audioChannels = session.TranscodingInfo.AudioChannels; + } + + if (videoCodec) { + + sessionStats.push({ + label: 'Video codec:', + value: session.TranscodingInfo.IsVideoDirect ? (videoCodec.toUpperCase() + ' (direct)') : videoCodec.toUpperCase() + }); + } + + if (audioCodec) { + + sessionStats.push({ + label: 'Audio codec:', + value: session.TranscodingInfo.IsAudioDirect ? (audioCodec.toUpperCase() + ' (direct)') : audioCodec.toUpperCase() + }); + } + + //if (audioChannels) { + + // sessionStats.push({ + // label: 'Audio channels:', + // value: audioChannels + // }); + //} + + if (displayPlayMethod === 'Transcode') { + if (totalBitrate) { + + sessionStats.push({ + label: 'Bitrate:', + value: getDisplayBitrate(totalBitrate) + }); + } + if (session.TranscodingInfo.CompletionPercentage) { + + sessionStats.push({ + label: 'Transcoding progress:', + value: session.TranscodingInfo.CompletionPercentage.toFixed(1) + '%' + }); + } + if (session.TranscodingInfo.Framerate) { + + sessionStats.push({ + label: 'Transcoding framerate:', + value: session.TranscodingInfo.Framerate + ' fps' + }); + } + if (session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length) { + + sessionStats.push({ + label: 'Reason for transcoding:', + value: session.TranscodingInfo.TranscodeReasons.map(translateReason).join('
') + }); + } + } + + return sessionStats; } function getDisplayBitrate(bitrate) { - return bitrate > 1e6 ? (bitrate / 1e6).toFixed(1) + " Mbps" : Math.floor(bitrate / 1e3) + " kbps" + + if (bitrate > 1000000) { + return (bitrate / 1000000).toFixed(1) + ' Mbps'; + } else { + return Math.floor(bitrate / 1000) + ' kbps'; + } } function getMediaSourceStats(session, player, displayPlayMethod) { - var sessionStats = [], - mediaSource = playbackManager.currentMediaSource(player) || {}, - totalBitrate = mediaSource.Bitrate; - mediaSource.Container && sessionStats.push({ - label: "Container:", - value: mediaSource.Container - }), totalBitrate && sessionStats.push({ - label: "Bitrate:", - value: getDisplayBitrate(totalBitrate) - }); - var mediaStreams = mediaSource.MediaStreams || [], - videoStream = mediaStreams.filter(function(s) { - return "Video" === s.Type - })[0] || {}, - videoCodec = videoStream.Codec, - audioStreamIndex = playbackManager.getAudioStreamIndex(player), - audioStream = playbackManager.audioTracks(player).filter(function(s) { - return "Audio" === s.Type && s.Index === audioStreamIndex - })[0] || {}, - audioCodec = audioStream.Codec, - audioChannels = audioStream.Channels, - videoInfos = []; - videoCodec && videoInfos.push(videoCodec.toUpperCase()), videoStream.Profile && videoInfos.push(videoStream.Profile), videoInfos.length && sessionStats.push({ - label: "Video codec:", - value: videoInfos.join(" ") - }), videoStream.BitRate && sessionStats.push({ - label: "Video bitrate:", - value: getDisplayBitrate(videoStream.BitRate) - }); + + var sessionStats = []; + + var mediaSource = playbackManager.currentMediaSource(player) || {}; + var totalBitrate = mediaSource.Bitrate; + + if (mediaSource.Container) { + sessionStats.push({ + label: 'Container:', + value: mediaSource.Container + }); + } + + if (totalBitrate) { + + sessionStats.push({ + label: 'Bitrate:', + value: getDisplayBitrate(totalBitrate) + }); + } + + var mediaStreams = mediaSource.MediaStreams || []; + var videoStream = mediaStreams.filter(function (s) { + + return s.Type === 'Video'; + + })[0] || {}; + + var videoCodec = videoStream.Codec; + + var audioStreamIndex = playbackManager.getAudioStreamIndex(player); + var audioStream = playbackManager.audioTracks(player).filter(function (s) { + + return s.Type === 'Audio' && s.Index === audioStreamIndex; + + })[0] || {}; + + var audioCodec = audioStream.Codec; + var audioChannels = audioStream.Channels; + + var videoInfos = []; + + if (videoCodec) { + videoInfos.push(videoCodec.toUpperCase()); + } + + if (videoStream.Profile) { + videoInfos.push(videoStream.Profile); + } + + if (videoInfos.length) { + sessionStats.push({ + label: 'Video codec:', + value: videoInfos.join(' ') + }); + } + + if (videoStream.BitRate) { + sessionStats.push({ + label: 'Video bitrate:', + value: getDisplayBitrate(videoStream.BitRate) + }); + } + var audioInfos = []; - return audioCodec && audioInfos.push(audioCodec.toUpperCase()), audioStream.Profile && audioInfos.push(audioStream.Profile), audioInfos.length && sessionStats.push({ - label: "Audio codec:", - value: audioInfos.join(" ") - }), audioStream.BitRate && sessionStats.push({ - label: "Audio bitrate:", - value: getDisplayBitrate(audioStream.BitRate) - }), audioChannels && sessionStats.push({ - label: "Audio channels:", - value: audioChannels - }), audioStream.SampleRate && sessionStats.push({ - label: "Audio sample rate:", - value: audioStream.SampleRate + " Hz" - }), audioStream.BitDepth && sessionStats.push({ - label: "Audio bit depth:", - value: audioStream.BitDepth - }), sessionStats + + if (audioCodec) { + audioInfos.push(audioCodec.toUpperCase()); + } + + if (audioStream.Profile) { + audioInfos.push(audioStream.Profile); + } + + if (audioInfos.length) { + sessionStats.push({ + label: 'Audio codec:', + value: audioInfos.join(' ') + }); + } + + if (audioStream.BitRate) { + sessionStats.push({ + label: 'Audio bitrate:', + value: getDisplayBitrate(audioStream.BitRate) + }); + } + + if (audioChannels) { + sessionStats.push({ + label: 'Audio channels:', + value: audioChannels + }); + } + + if (audioStream.SampleRate) { + sessionStats.push({ + label: 'Audio sample rate:', + value: audioStream.SampleRate + ' Hz' + }); + } + + if (audioStream.BitDepth) { + sessionStats.push({ + label: 'Audio bit depth:', + value: audioStream.BitDepth + }); + } + + return sessionStats; } function getStats(instance, player) { - var statsPromise = player.getStats ? player.getStats() : Promise.resolve({}), - sessionPromise = getSession(instance, player); - return Promise.all([statsPromise, sessionPromise]).then(function(responses) { - var playerStatsResult = responses[0], - playerStats = playerStatsResult.categories || [], - session = responses[1], - displayPlayMethod = playMethodHelper.getDisplayPlayMethod(session), - baseCategory = { - stats: [], - name: "Playback Info" - }; + + var statsPromise = player.getStats ? player.getStats() : Promise.resolve({}); + var sessionPromise = getSession(instance, player); + + return Promise.all([statsPromise, sessionPromise]).then(function (responses) { + + var playerStatsResult = responses[0]; + var playerStats = playerStatsResult.categories || []; + var session = responses[1]; + + var displayPlayMethod = playMethodHelper.getDisplayPlayMethod(session); + + var baseCategory = { + stats: [], + name: 'Playback Info' + }; + baseCategory.stats.unshift({ - label: "Play method:", + label: 'Play method:', value: displayPlayMethod - }), baseCategory.stats.unshift({ - label: "Player:", + }); + + baseCategory.stats.unshift({ + label: 'Player:', value: player.name }); + var categories = []; + categories.push(baseCategory); + for (var i = 0, length = playerStats.length; i < length; i++) { + var category = playerStats[i]; - "audio" === category.type ? category.name = "Audio Info" : "video" === category.type && (category.name = "Video Info"), categories.push(category) + if (category.type === 'audio') { + category.name = 'Audio Info'; + } + else if (category.type === 'video') { + category.name = 'Video Info'; + } + categories.push(category); } - return session.TranscodingInfo && categories.push({ - stats: getTranscodingStats(session, player, displayPlayMethod), - name: "Transcode" === displayPlayMethod ? "Transcoding Info" : "Direct Stream Info" - }), categories.push({ + + if (session.TranscodingInfo) { + + categories.push({ + stats: getTranscodingStats(session, player, displayPlayMethod), + name: displayPlayMethod === 'Transcode' ? 'Transcoding Info' : 'Direct Stream Info' + }); + } + + categories.push({ stats: getMediaSourceStats(session, player), - name: "Original Media Info" - }), Promise.resolve(categories) - }) + name: 'Original Media Info' + }); + + return Promise.resolve(categories); + }); } function renderPlayerStats(instance, player) { - var now = (new Date).getTime(); - now - (instance.lastRender || 0) < 700 || (instance.lastRender = now, getStats(instance, player).then(function(stats) { + + var now = new Date().getTime(); + + if ((now - (instance.lastRender || 0)) < 700) { + return; + } + + instance.lastRender = now; + + getStats(instance, player).then(function (stats) { + var elem = instance.element; - elem && renderStats(elem, stats) - })) + if (!elem) { + return; + } + + renderStats(elem, stats); + }); } function bindEvents(instance, player) { - var localOnTimeUpdate = function() { - renderPlayerStats(instance, player) + + var localOnTimeUpdate = function () { + renderPlayerStats(instance, player); }; - instance.onTimeUpdate = localOnTimeUpdate, events.on(player, "timeupdate", localOnTimeUpdate) + + instance.onTimeUpdate = localOnTimeUpdate; + events.on(player, 'timeupdate', localOnTimeUpdate); } function unbindEvents(instance, player) { + var localOnTimeUpdate = instance.onTimeUpdate; - localOnTimeUpdate && events.off(player, "timeupdate", localOnTimeUpdate) + + if (localOnTimeUpdate) { + events.off(player, 'timeupdate', localOnTimeUpdate); + } } function PlayerStats(options) { - this.options = options, init(this), this.enabled(!0) + + this.options = options; + + init(this); + + this.enabled(true); } - return PlayerStats.prototype.enabled = function(enabled) { - if (null == enabled) return this._enabled; + + PlayerStats.prototype.enabled = function (enabled) { + + if (enabled == null) { + return this._enabled; + } + var options = this.options; - options && (this._enabled = enabled, enabled ? (this.element.classList.remove("hide"), bindEvents(this, options.player)) : (this.element.classList.add("hide"), unbindEvents(this, options.player))) - }, PlayerStats.prototype.toggle = function() { - this.enabled(!this.enabled()) - }, PlayerStats.prototype.destroy = function() { + + if (!options) { + return; + } + + this._enabled = enabled; + if (enabled) { + this.element.classList.remove('hide'); + bindEvents(this, options.player); + } else { + this.element.classList.add('hide'); + unbindEvents(this, options.player); + } + }; + + PlayerStats.prototype.toggle = function () { + this.enabled(!this.enabled()); + }; + + PlayerStats.prototype.destroy = function () { + var options = this.options; - options && (this.options = null, unbindEvents(this, options.player)); + + if (options) { + + this.options = null; + unbindEvents(this, options.player); + } + var elem = this.element; - elem && (elem.parentNode.removeChild(elem), this.element = null) - }, PlayerStats + if (elem) { + elem.parentNode.removeChild(elem); + this.element = null; + } + }; + + return PlayerStats; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playlisteditor/playlisteditor.js b/src/bower_components/emby-webcomponents/playlisteditor/playlisteditor.js index 22a5c180d8..a2fd9a1a33 100644 --- a/src/bower_components/emby-webcomponents/playlisteditor/playlisteditor.js +++ b/src/bower_components/emby-webcomponents/playlisteditor/playlisteditor.js @@ -1,127 +1,298 @@ -define(["shell", "dialogHelper", "loading", "layoutManager", "playbackManager", "connectionManager", "userSettings", "appRouter", "globalize", "emby-input", "paper-icon-button-light", "emby-select", "material-icons", "css!./../formdialog", "emby-button"], function(shell, dialogHelper, loading, layoutManager, playbackManager, connectionManager, userSettings, appRouter, globalize) { - "use strict"; +define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', 'connectionManager', 'userSettings', 'appRouter', 'globalize', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button'], function (shell, dialogHelper, loading, layoutManager, playbackManager, connectionManager, userSettings, appRouter, globalize) { + 'use strict'; + + var currentServerId; function parentWithClass(elem, className) { - for (; !elem.classList || !elem.classList.contains(className);) - if (!(elem = elem.parentNode)) return null; - return elem + + while (!elem.classList || !elem.classList.contains(className)) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; } function onSubmit(e) { - var panel = parentWithClass(this, "dialog"), - playlistId = panel.querySelector("#selectPlaylistToAddTo").value, - apiClient = connectionManager.getApiClient(currentServerId); - return playlistId ? (userSettings.set("playlisteditor-lastplaylistid", playlistId), addToPlaylist(apiClient, panel, playlistId)) : createPlaylist(apiClient, panel), e.preventDefault(), !1 + + var panel = parentWithClass(this, 'dialog'); + + var playlistId = panel.querySelector('#selectPlaylistToAddTo').value; + var apiClient = connectionManager.getApiClient(currentServerId); + + if (playlistId) { + userSettings.set('playlisteditor-lastplaylistid', playlistId); + addToPlaylist(apiClient, panel, playlistId); + } else { + createPlaylist(apiClient, panel); + } + + e.preventDefault(); + return false; } function createPlaylist(apiClient, dlg) { + loading.show(); + var url = apiClient.getUrl("Playlists", { - Name: dlg.querySelector("#txtNewPlaylistName").value, - Ids: dlg.querySelector(".fldSelectedItemIds").value || "", + + Name: dlg.querySelector('#txtNewPlaylistName').value, + Ids: dlg.querySelector('.fldSelectedItemIds').value || '', userId: apiClient.getCurrentUserId() + }); + apiClient.ajax({ type: "POST", url: url, dataType: "json" - }).then(function(result) { + + }).then(function (result) { + loading.hide(); + var id = result.Id; - dlg.submitted = !0, dialogHelper.close(dlg), redirectToPlaylist(apiClient, id) - }) + dlg.submitted = true; + dialogHelper.close(dlg); + redirectToPlaylist(apiClient, id); + }); } function redirectToPlaylist(apiClient, id) { - appRouter.showItem(id, apiClient.serverId()) + + appRouter.showItem(id, apiClient.serverId()); } function addToPlaylist(apiClient, dlg, id) { - var itemIds = dlg.querySelector(".fldSelectedItemIds").value || ""; - if ("queue" === id) return playbackManager.queue({ - serverId: apiClient.serverId(), - ids: itemIds.split(",") - }), dlg.submitted = !0, void dialogHelper.close(dlg); + + var itemIds = dlg.querySelector('.fldSelectedItemIds').value || ''; + + if (id === 'queue') { + + playbackManager.queue({ + serverId: apiClient.serverId(), + ids: itemIds.split(',') + }); + dlg.submitted = true; + dialogHelper.close(dlg); + return; + } + loading.show(); + var url = apiClient.getUrl("Playlists/" + id + "/Items", { + Ids: itemIds, userId: apiClient.getCurrentUserId() }); + apiClient.ajax({ type: "POST", url: url - }).then(function() { - loading.hide(), dlg.submitted = !0, dialogHelper.close(dlg) - }) + + }).then(function () { + + loading.hide(); + + dlg.submitted = true; + dialogHelper.close(dlg); + }); } function triggerChange(select) { - select.dispatchEvent(new CustomEvent("change", {})) + select.dispatchEvent(new CustomEvent('change', {})); } function populatePlaylists(editorOptions, panel) { - var select = panel.querySelector("#selectPlaylistToAddTo"); - loading.hide(), panel.querySelector(".newPlaylistInfo").classList.add("hide"); + + var select = panel.querySelector('#selectPlaylistToAddTo'); + + loading.hide(); + + panel.querySelector('.newPlaylistInfo').classList.add('hide'); + var options = { - Recursive: !0, - IncludeItemTypes: "Playlist", - SortBy: "SortName", - EnableTotalRecordCount: !1 - }, - apiClient = connectionManager.getApiClient(currentServerId); - apiClient.getItems(apiClient.getCurrentUserId(), options).then(function(result) { - var html = ""; - !1 !== editorOptions.enableAddToPlayQueue && playbackManager.isPlaying() && (html += '"), html += '", html += result.Items.map(function(i) { - return '" - }), select.innerHTML = html; + + Recursive: true, + IncludeItemTypes: "Playlist", + SortBy: 'SortName', + EnableTotalRecordCount: false + }; + + var apiClient = connectionManager.getApiClient(currentServerId); + apiClient.getItems(apiClient.getCurrentUserId(), options).then(function (result) { + + var html = ''; + + if (editorOptions.enableAddToPlayQueue !== false && playbackManager.isPlaying()) { + html += ''; + } + + html += ''; + + html += result.Items.map(function (i) { + + return ''; + }); + + select.innerHTML = html; + var defaultValue = editorOptions.defaultValue; - defaultValue || (defaultValue = userSettings.get("playlisteditor-lastplaylistid") || ""), select.value = "new" === defaultValue ? "" : defaultValue, select.value || (select.value = ""), triggerChange(select), loading.hide() - }) + if (!defaultValue) { + defaultValue = userSettings.get('playlisteditor-lastplaylistid') || ''; + } + select.value = defaultValue === 'new' ? '' : defaultValue; + + // 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(); + }); } function getEditorHtml(items) { - var html = ""; - html += '
', html += '
', html += '
', html += '
'; - var autoFocus = items.length ? " autofocus" : ""; - return html += '", html += "
", html += '
', html += '
', autoFocus = items.length ? "" : " autofocus", html += '", html += "
", html += "
", html += '
', html += '", html += "
", html += '', html += "
", html += "
", html += "
" + + var html = ''; + + html += '
'; + html += '
'; + html += '
'; + + html += '
'; + var autoFocus = items.length ? ' autofocus' : ''; + html += ''; + html += '
'; + + html += '
'; + + html += '
'; + autoFocus = items.length ? '' : ' autofocus'; + html += ''; + html += '
'; + + // newPlaylistInfo + html += '
'; + + html += '
'; + html += ''; + html += '
'; + + html += ''; + + html += '
'; + html += '
'; + html += '
'; + + return html; } function initEditor(content, options, items) { - if (content.querySelector("#selectPlaylistToAddTo").addEventListener("change", function() { - this.value ? (content.querySelector(".newPlaylistInfo").classList.add("hide"), content.querySelector("#txtNewPlaylistName").removeAttribute("required")) : (content.querySelector(".newPlaylistInfo").classList.remove("hide"), content.querySelector("#txtNewPlaylistName").setAttribute("required", "required")) - }), content.querySelector("form").addEventListener("submit", onSubmit), content.querySelector(".fldSelectedItemIds", content).value = items.join(","), items.length) content.querySelector(".fldSelectPlaylist").classList.remove("hide"), populatePlaylists(options, content); - else { - content.querySelector(".fldSelectPlaylist").classList.add("hide"); - var selectPlaylistToAddTo = content.querySelector("#selectPlaylistToAddTo"); - selectPlaylistToAddTo.innerHTML = "", selectPlaylistToAddTo.value = "", triggerChange(selectPlaylistToAddTo) + + content.querySelector('#selectPlaylistToAddTo').addEventListener('change', function () { + if (this.value) { + content.querySelector('.newPlaylistInfo').classList.add('hide'); + content.querySelector('#txtNewPlaylistName').removeAttribute('required'); + } else { + content.querySelector('.newPlaylistInfo').classList.remove('hide'); + content.querySelector('#txtNewPlaylistName').setAttribute('required', 'required'); + } + }); + + content.querySelector('form').addEventListener('submit', onSubmit); + + content.querySelector('.fldSelectedItemIds', content).value = items.join(','); + + if (items.length) { + content.querySelector('.fldSelectPlaylist').classList.remove('hide'); + populatePlaylists(options, content); + } else { + content.querySelector('.fldSelectPlaylist').classList.add('hide'); + + var selectPlaylistToAddTo = content.querySelector('#selectPlaylistToAddTo'); + selectPlaylistToAddTo.innerHTML = ''; + selectPlaylistToAddTo.value = ''; + triggerChange(selectPlaylistToAddTo); } } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } - function PlaylistEditor() {} - var currentServerId; - return PlaylistEditor.prototype.show = function(options) { + function PlaylistEditor() { + + } + + PlaylistEditor.prototype.show = function (options) { + var items = options.items || {}; currentServerId = options.serverId; + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'small'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - var html = "", - title = globalize.translate("sharedcomponents#HeaderAddToPlaylist"); - return html += '
', html += '', html += '

', html += title, html += "

", html += "
", html += getEditorHtml(items), dlg.innerHTML = html, initEditor(dlg, options, items), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), dialogHelper.open(dlg).then(function() { - return layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), dlg.submitted ? Promise.resolve() : Promise.reject() - }) - }, PlaylistEditor + + dlg.classList.add('formDialog'); + + var html = ''; + var title = globalize.translate('sharedcomponents#HeaderAddToPlaylist'); + + html += '
'; + html += ''; + html += '

'; + html += title; + html += '

'; + + html += '
'; + + html += getEditorHtml(items); + + dlg.innerHTML = html; + + initEditor(dlg, options, items); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + + return dialogHelper.open(dlg).then(function () { + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + if (dlg.submitted) { + return Promise.resolve(); + } + + return Promise.reject(); + }); + }; + + return PlaylistEditor; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/playmenu.js b/src/bower_components/emby-webcomponents/playmenu.js index acdf9e8f7e..097c17f71a 100644 --- a/src/bower_components/emby-webcomponents/playmenu.js +++ b/src/bower_components/emby-webcomponents/playmenu.js @@ -1,55 +1,75 @@ -define(["actionsheet", "datetime", "playbackManager", "globalize", "appSettings"], function(actionsheet, datetime, playbackManager, globalize, appSettings) { - "use strict"; +define(['actionsheet', 'datetime', 'playbackManager', 'globalize', 'appSettings'], function (actionsheet, datetime, playbackManager, globalize, appSettings) { + 'use strict'; function show(options) { - var item = options.item, - itemType = item.Type, - isFolder = item.IsFolder, - itemId = item.Id, - channelId = item.ChannelId, - serverId = item.ServerId, - resumePositionTicks = item.UserData ? item.UserData.PlaybackPositionTicks : null, - playableItemId = "Program" === itemType ? channelId : itemId; - if (!resumePositionTicks || isFolder) return void playbackManager.play({ - ids: [playableItemId], - serverId: serverId - }); + + var item = options.item; + + var itemType = item.Type; + var isFolder = item.IsFolder; + var itemId = item.Id; + var channelId = item.ChannelId; + var serverId = item.ServerId; + var resumePositionTicks = item.UserData ? item.UserData.PlaybackPositionTicks : null; + + var playableItemId = itemType === 'Program' ? channelId : itemId; + + if (!resumePositionTicks || isFolder) { + playbackManager.play({ + ids: [playableItemId], + serverId: serverId + }); + return; + } + var menuItems = []; + menuItems.push({ - name: globalize.translate("sharedcomponents#ResumeAt", datetime.getDisplayRunningTime(resumePositionTicks)), - id: "resume" - }), menuItems.push({ - name: globalize.translate("sharedcomponents#PlayFromBeginning"), - id: "play" - }), actionsheet.show({ + name: globalize.translate('sharedcomponents#ResumeAt', datetime.getDisplayRunningTime(resumePositionTicks)), + id: 'resume' + }); + + menuItems.push({ + name: globalize.translate('sharedcomponents#PlayFromBeginning'), + id: 'play' + }); + + actionsheet.show({ + items: menuItems, positionTo: options.positionTo - }).then(function(id) { + + }).then(function (id) { switch (id) { - case "play": + + case 'play': playbackManager.play({ ids: [playableItemId], serverId: serverId }); break; - case "resume": + case 'resume': playbackManager.play({ ids: [playableItemId], startPositionTicks: resumePositionTicks, serverId: serverId }); break; - case "queue": + case 'queue': playbackManager.queue({ items: [item] }); break; - case "shuffle": - playbackManager.shuffle(item) + case 'shuffle': + playbackManager.shuffle(item); + break; + default: + break; } - }) + }); } + return { show: show - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/pluginmanager.js b/src/bower_components/emby-webcomponents/pluginmanager.js index 57da495a42..ec65e63e65 100644 --- a/src/bower_components/emby-webcomponents/pluginmanager.js +++ b/src/bower_components/emby-webcomponents/pluginmanager.js @@ -1,63 +1,149 @@ -define(["events"], function(events) { - "use strict"; +define(['events'], function (events) { + 'use strict'; + + // TODO: replace with each plugin version + var cacheParam = new Date().getTime(); function loadStrings(plugin, globalize) { var strings = plugin.getTranslations ? plugin.getTranslations() : []; return globalize.loadStrings({ name: plugin.id || plugin.packageName, strings: strings - }) + }); } function definePluginRoute(pluginManager, route, plugin) { - route.contentPath = pluginManager.mapPath(plugin, route.path), route.path = pluginManager.mapRoute(plugin, route), Emby.App.defineRoute(route, plugin.id) + + route.contentPath = pluginManager.mapPath(plugin, route.path); + route.path = pluginManager.mapRoute(plugin, route); + + Emby.App.defineRoute(route, plugin.id); } function PluginManager() { - this.pluginsList = [] + + this.pluginsList = []; } - var cacheParam = (new Date).getTime(); - return PluginManager.prototype.loadPlugin = function(url) { - console.log("Loading plugin: " + url); + + PluginManager.prototype.loadPlugin = function (url) { + + console.log('Loading plugin: ' + url); var instance = this; - return new Promise(function(resolve, reject) { - require([url, "globalize", "appRouter"], function(pluginFactory, globalize, appRouter) { - var plugin = new pluginFactory; - if (instance.pluginsList.filter(function(p) { - return p.id === plugin.id - })[0]) return void resolve(url); + + return new Promise(function (resolve, reject) { + + require([url, 'globalize', 'appRouter'], function (pluginFactory, globalize, appRouter) { + + var plugin = new pluginFactory(); + + // See if it's already installed + var existing = instance.pluginsList.filter(function (p) { + return p.id === plugin.id; + })[0]; + + if (existing) { + resolve(url); + return; + } + plugin.installUrl = url; - var urlLower = url.toLowerCase(); - 1 === urlLower.indexOf("http:") && -1 === urlLower.indexOf("https:") && -1 === urlLower.indexOf("file:") && 0 !== url.indexOf(appRouter.baseUrl()) && (url = appRouter.baseUrl() + "/" + url); - var separatorIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\")); + + var urlLower = url.toLowerCase(); + if (urlLower.indexOf('http:') === -1 && urlLower.indexOf('https:') === -1 && urlLower.indexOf('file:') === -1) { + if (url.indexOf(appRouter.baseUrl()) !== 0) { + + url = appRouter.baseUrl() + '/' + url; + } + } + + var separatorIndex = Math.max(url.lastIndexOf('/'), url.lastIndexOf('\\')); plugin.baseUrl = url.substring(0, separatorIndex); + var paths = {}; - paths[plugin.id] = plugin.baseUrl, requirejs.config({ + paths[plugin.id] = plugin.baseUrl; + + requirejs.config({ waitSeconds: 0, paths: paths - }), instance.register(plugin), plugin.getRoutes && plugin.getRoutes().forEach(function(route) { - definePluginRoute(instance, route, plugin) - }), "skin" === plugin.type ? resolve(plugin) : loadStrings(plugin, globalize).then(function() { - resolve(plugin) - }, reject) - }) - }) - }, PluginManager.prototype.register = function(obj) { - this.pluginsList.push(obj), events.trigger(this, "registered", [obj]) - }, PluginManager.prototype.ofType = function(type) { - return this.pluginsList.filter(function(o) { - return o.type === type - }) - }, PluginManager.prototype.plugins = function() { - return this.pluginsList - }, PluginManager.prototype.mapRoute = function(plugin, route) { - return "string" == typeof plugin && (plugin = this.pluginsList.filter(function(p) { - return (p.id || p.packageName) === plugin - })[0]), route = route.path || route, 0 === route.toLowerCase().indexOf("http") ? route : "/plugins/" + plugin.id + "/" + route - }, PluginManager.prototype.mapPath = function(plugin, path, addCacheParam) { - "string" == typeof plugin && (plugin = this.pluginsList.filter(function(p) { - return (p.id || p.packageName) === plugin - })[0]); - var url = plugin.baseUrl + "/" + path; - return addCacheParam && (url += -1 === url.indexOf("?") ? "?" : "&", url += "v=" + cacheParam), url - }, new PluginManager + }); + + instance.register(plugin); + + if (plugin.getRoutes) { + plugin.getRoutes().forEach(function (route) { + definePluginRoute(instance, route, plugin); + }); + } + + if (plugin.type === 'skin') { + + // translations won't be loaded for skins until needed + resolve(plugin); + } else { + + loadStrings(plugin, globalize).then(function () { + resolve(plugin); + }, reject); + } + }); + }); + }; + + // In lieu of automatic discovery, plugins will register dynamic objects + // Each object will have the following properties: + // name + // type (skin, screensaver, etc) + PluginManager.prototype.register = function (obj) { + + this.pluginsList.push(obj); + events.trigger(this, 'registered', [obj]); + }; + + PluginManager.prototype.ofType = function (type) { + + return this.pluginsList.filter(function (o) { + return o.type === type; + }); + }; + + PluginManager.prototype.plugins = function () { + return this.pluginsList; + }; + + PluginManager.prototype.mapRoute = function (plugin, route) { + + if (typeof plugin === 'string') { + plugin = this.pluginsList.filter(function (p) { + return (p.id || p.packageName) === plugin; + })[0]; + } + + route = route.path || route; + + if (route.toLowerCase().indexOf('http') === 0) { + return route; + } + + return '/plugins/' + plugin.id + '/' + route; + }; + + PluginManager.prototype.mapPath = function (plugin, path, addCacheParam) { + + if (typeof plugin === 'string') { + plugin = this.pluginsList.filter(function (p) { + return (p.id || p.packageName) === plugin; + })[0]; + } + + var url = plugin.baseUrl + '/' + path; + + if (addCacheParam) { + url += url.indexOf('?') === -1 ? '?' : '&'; + url += 'v=' + cacheParam; + } + + return url; + }; + + return new PluginManager(); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/polyfills/array.js b/src/bower_components/emby-webcomponents/polyfills/array.js index e32a7d9562..5caea62e3b 100644 --- a/src/bower_components/emby-webcomponents/polyfills/array.js +++ b/src/bower_components/emby-webcomponents/polyfills/array.js @@ -1,12 +1,25 @@ -Array.prototype.filter || (Array.prototype.filter = function(fun) { - "use strict"; - if (null == this) throw new TypeError; - var t = Object(this), - len = t.length >>> 0; - if ("function" != typeof fun) throw new TypeError; - for (var res = [], thisp = arguments[1], i = 0; i < len; i++) - if (i in t) { - var val = t[i]; - fun.call(thisp, val, i, t) && res.push(val) - } return res -}); \ No newline at end of file +if (!Array.prototype.filter) { + Array.prototype.filter = function (fun /*, thisp*/) { + "use strict"; + + if (this == null) + throw new TypeError(); + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") + throw new TypeError(); + + var res = []; + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in t) { + var val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) + res.push(val); + } + } + + return res; + }; +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/polyfills/bind.js b/src/bower_components/emby-webcomponents/polyfills/bind.js index 27b00f6eae..82495aa103 100644 --- a/src/bower_components/emby-webcomponents/polyfills/bind.js +++ b/src/bower_components/emby-webcomponents/polyfills/bind.js @@ -1,10 +1,27 @@ -Function.prototype.bind || (Function.prototype.bind = function(oThis) { - if ("function" != typeof this) throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function() {}, - fBound = function() { - return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))) - }; - return this.prototype && (fNOP.prototype = this.prototype), fBound.prototype = new fNOP, fBound -}); \ No newline at end of file +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== 'function') { + // closest thing possible to the ECMAScript 5 + // internal IsCallable function + throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () { }, + fBound = function () { + return fToBind.apply(this instanceof fNOP + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + if (this.prototype) { + // Function.prototype doesn't have a prototype property + fNOP.prototype = this.prototype; + } + fBound.prototype = new fNOP(); + + return fBound; + }; +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/polyfills/objectassign.js b/src/bower_components/emby-webcomponents/polyfills/objectassign.js index 7883d26563..79568f8cba 100644 --- a/src/bower_components/emby-webcomponents/polyfills/objectassign.js +++ b/src/bower_components/emby-webcomponents/polyfills/objectassign.js @@ -1,12 +1,23 @@ -"function" != typeof Object.assign && function() { - Object.assign = function(target) { - "use strict"; - if (void 0 === target || null === target) throw new TypeError("Cannot convert undefined or null to object"); - for (var output = Object(target), index = 1; index < arguments.length; index++) { - var source = arguments[index]; - if (void 0 !== source && null !== source) - for (var nextKey in source) source.hasOwnProperty(nextKey) && (output[nextKey] = source[nextKey]) - } - return output - } -}(); \ No newline at end of file +if (typeof Object.assign != 'function') { + (function () { + Object.assign = function (target) { + 'use strict'; + if (target === undefined || target === null) { + throw new TypeError('Cannot convert undefined or null to object'); + } + + var output = Object(target); + for (var index = 1; index < arguments.length; index++) { + var source = arguments[index]; + if (source !== undefined && source !== null) { + for (var nextKey in source) { + if (source.hasOwnProperty(nextKey)) { + output[nextKey] = source[nextKey]; + } + } + } + } + return output; + }; + })(); +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/polyfills/raf.js b/src/bower_components/emby-webcomponents/polyfills/raf.js index 64b4a78435..a856f6a76a 100644 --- a/src/bower_components/emby-webcomponents/polyfills/raf.js +++ b/src/bower_components/emby-webcomponents/polyfills/raf.js @@ -1,13 +1,31 @@ -! function() { - for (var lastTime = 0, vendors = ["ms", "moz", "webkit", "o"], x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) window.requestAnimationFrame = window[vendors[x] + "RequestAnimationFrame"], window.cancelAnimationFrame = window[vendors[x] + "CancelAnimationFrame"] || window[vendors[x] + "CancelRequestAnimationFrame"]; - window.requestAnimationFrame || (window.requestAnimationFrame = function(callback, element) { - var currTime = (new Date).getTime(), - timeToCall = Math.max(0, 16 - (currTime - lastTime)), - id = window.setTimeout(function() { - callback(currTime + timeToCall) - }, timeToCall); - return lastTime = currTime + timeToCall, id - }), window.cancelAnimationFrame || (window.cancelAnimationFrame = function(id) { - clearTimeout(id) - }) -}(); \ No newline at end of file +// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ +// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + +// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel + +// MIT license + +(function () { + var lastTime = 0; + var vendors = ['ms', 'moz', 'webkit', 'o']; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] + || window[vendors[x] + 'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function () { callback(currTime + timeToCall); }, + timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; +}()); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/prompt/nativeprompt.js b/src/bower_components/emby-webcomponents/prompt/nativeprompt.js index b38237c1f8..b0634bd428 100644 --- a/src/bower_components/emby-webcomponents/prompt/nativeprompt.js +++ b/src/bower_components/emby-webcomponents/prompt/nativeprompt.js @@ -1,16 +1,28 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; function replaceAll(str, find, replace) { - return str.split(find).join(replace) - } - return function(options) { - "string" == typeof options && (options = { - label: "", - text: options - }); - var label = replaceAll(options.label || "", "
", "\n"), - result = prompt(label, options.text || ""); - return result ? Promise.resolve(result) : Promise.reject(result) + + return str.split(find).join(replace); } + + return function (options) { + + if (typeof options === 'string') { + options = { + label: '', + text: options + }; + } + + var label = replaceAll(options.label || '', '
', '\n'); + + var result = prompt(label, options.text || ''); + + if (result) { + return Promise.resolve(result); + } else { + return Promise.reject(result); + } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/prompt/prompt.js b/src/bower_components/emby-webcomponents/prompt/prompt.js index d70ed5d6bc..6d3d6b246f 100644 --- a/src/bower_components/emby-webcomponents/prompt/prompt.js +++ b/src/bower_components/emby-webcomponents/prompt/prompt.js @@ -1,40 +1,104 @@ -define(["dialogHelper", "layoutManager", "scrollHelper", "globalize", "dom", "require", "material-icons", "emby-button", "paper-icon-button-light", "emby-input", "formDialogStyle"], function(dialogHelper, layoutManager, scrollHelper, globalize, dom, require) { - "use strict"; +define(['dialogHelper', 'layoutManager', 'scrollHelper', 'globalize', 'dom', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle'], function (dialogHelper, layoutManager, scrollHelper, globalize, dom, require) { + 'use strict'; function setInputProperties(dlg, options) { - var txtInput = dlg.querySelector("#txtInput"); - txtInput.label ? txtInput.label(options.label || "") : txtInput.setAttribute("label", options.label || ""), txtInput.value = options.value || "" + var txtInput = dlg.querySelector('#txtInput'); + + if (txtInput.label) { + txtInput.label(options.label || ''); + } else { + txtInput.setAttribute('label', options.label || ''); + } + txtInput.value = options.value || ''; } function showDialog(options, template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv && (dialogOptions.size = "fullscreen"); + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateHtml(template, "sharedcomponents"), layoutManager.tv ? scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1) : (dlg.querySelector(".dialogContentInner").classList.add("dialogContentInner-mini"), dlg.classList.add("dialog-fullscreen-lowres")), dlg.querySelector(".btnCancel").addEventListener("click", function(e) { - dialogHelper.close(dlg) - }), dlg.querySelector(".formDialogHeaderTitle").innerHTML = options.title || "", options.description ? dlg.querySelector(".fieldDescription").innerHTML = options.description : dlg.querySelector(".fieldDescription").classList.add("hide"), setInputProperties(dlg, options); + + dlg.classList.add('formDialog'); + + dlg.innerHTML = globalize.translateHtml(template, 'sharedcomponents'); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); + } else { + dlg.querySelector('.dialogContentInner').classList.add('dialogContentInner-mini'); + dlg.classList.add('dialog-fullscreen-lowres'); + } + + dlg.querySelector('.btnCancel').addEventListener('click', function (e) { + dialogHelper.close(dlg); + }); + + dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || ''; + + if (options.description) { + dlg.querySelector('.fieldDescription').innerHTML = options.description; + } else { + dlg.querySelector('.fieldDescription').classList.add('hide'); + } + + setInputProperties(dlg, options); + var submitValue; - return dlg.querySelector("form").addEventListener("submit", function(e) { - return submitValue = dlg.querySelector("#txtInput").value, e.preventDefault(), e.stopPropagation(), setTimeout(function() { - dialogHelper.close(dlg) - }, 300), !1 - }), dlg.querySelector(".submitText").innerHTML = options.confirmText || globalize.translate("sharedcomponents#ButtonOk"), dlg.style.minWidth = Math.min(400, dom.getWindowSize().innerWidth - 50) + "px", dialogHelper.open(dlg).then(function() { - layoutManager.tv && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1); + + dlg.querySelector('form').addEventListener('submit', function (e) { + + submitValue = dlg.querySelector('#txtInput').value; + e.preventDefault(); + e.stopPropagation(); + + // Important, don't close the dialog until after the form has completed submitting, or it will cause an error in Chrome + setTimeout(function () { + dialogHelper.close(dlg); + }, 300); + + return false; + }); + + dlg.querySelector('.submitText').innerHTML = options.confirmText || globalize.translate('sharedcomponents#ButtonOk'); + + dlg.style.minWidth = (Math.min(400, dom.getWindowSize().innerWidth - 50)) + 'px'; + + return dialogHelper.open(dlg).then(function () { + + if (layoutManager.tv) { + scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); + } + var value = submitValue; - return value || Promise.reject() - }) - } - return function(options) { - return new Promise(function(resolve, reject) { - require(["text!./prompt.template.html"], function(template) { - "string" == typeof options && (options = { - title: "", - text: options - }), showDialog(options, template).then(resolve, reject) - }) - }) + + if (value) { + return value; + } else { + return Promise.reject(); + } + }); } + + return function (options) { + + return new Promise(function (resolve, reject) { + require(['text!./prompt.template.html'], function (template) { + + if (typeof options === 'string') { + options = { + title: '', + text: options + }; + } + showDialog(options, template).then(resolve, reject); + }); + }); + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/qualityoptions.js b/src/bower_components/emby-webcomponents/qualityoptions.js index d0d7bae88c..df88f0fac8 100644 --- a/src/bower_components/emby-webcomponents/qualityoptions.js +++ b/src/bower_components/emby-webcomponents/qualityoptions.js @@ -1,214 +1,163 @@ -define(["globalize"], function(globalize) { - "use strict"; +define(['globalize'], function (globalize) { + 'use strict'; function getVideoQualityOptions(options) { - var maxStreamingBitrate = options.currentMaxBitrate, - videoWidth = options.videoWidth, - maxAllowedWidth = videoWidth || 4096, - qualityOptions = []; - maxAllowedWidth >= 3800 && (qualityOptions.push({ - name: "4K - 120 Mbps", - maxHeight: 2160, - bitrate: 12e7 - }), qualityOptions.push({ - name: "4K - 100 Mbps", - maxHeight: 2160, - bitrate: 1e8 - }), qualityOptions.push({ - name: "4K - 80 Mbps", - maxHeight: 2160, - bitrate: 8e7 - })), maxAllowedWidth >= 1900 ? (qualityOptions.push({ - name: "1080p - 60 Mbps", - maxHeight: 1080, - bitrate: 6e7 - }), qualityOptions.push({ - name: "1080p - 50 Mbps", - maxHeight: 1080, - bitrate: 5e7 - }), qualityOptions.push({ - name: "1080p - 40 Mbps", - maxHeight: 1080, - bitrate: 4e7 - }), qualityOptions.push({ - name: "1080p - 30 Mbps", - maxHeight: 1080, - bitrate: 3e7 - }), qualityOptions.push({ - name: "1080p - 25 Mbps", - maxHeight: 1080, - bitrate: 25e6 - }), qualityOptions.push({ - name: "1080p - 20 Mbps", - maxHeight: 1080, - bitrate: 2e7 - }), qualityOptions.push({ - name: "1080p - 15 Mbps", - maxHeight: 1080, - bitrate: 15e6 - }), qualityOptions.push({ - name: "1080p - 10 Mbps", - maxHeight: 1080, - bitrate: 10000001 - }), qualityOptions.push({ - name: "1080p - 8 Mbps", - maxHeight: 1080, - bitrate: 8000001 - }), qualityOptions.push({ - name: "1080p - 6 Mbps", - maxHeight: 1080, - bitrate: 6000001 - }), qualityOptions.push({ - name: "1080p - 5 Mbps", - maxHeight: 1080, - bitrate: 5000001 - }), qualityOptions.push({ - name: "1080p - 4 Mbps", - maxHeight: 1080, - bitrate: 4000002 - })) : maxAllowedWidth >= 1260 ? (qualityOptions.push({ - name: "720p - 10 Mbps", - maxHeight: 720, - bitrate: 1e7 - }), qualityOptions.push({ - name: "720p - 8 Mbps", - maxHeight: 720, - bitrate: 8e6 - }), qualityOptions.push({ - name: "720p - 6 Mbps", - maxHeight: 720, - bitrate: 6e6 - }), qualityOptions.push({ - name: "720p - 5 Mbps", - maxHeight: 720, - bitrate: 5e6 - })) : maxAllowedWidth >= 620 && (qualityOptions.push({ - name: "480p - 4 Mbps", - maxHeight: 480, - bitrate: 4000001 - }), qualityOptions.push({ - name: "480p - 3 Mbps", - maxHeight: 480, - bitrate: 3000001 - }), qualityOptions.push({ - name: "480p - 2.5 Mbps", - maxHeight: 480, - bitrate: 25e5 - }), qualityOptions.push({ - name: "480p - 2 Mbps", - maxHeight: 480, - bitrate: 2000001 - }), qualityOptions.push({ - name: "480p - 1.5 Mbps", - maxHeight: 480, - bitrate: 1500001 - })), maxAllowedWidth >= 1260 && (qualityOptions.push({ - name: "720p - 4 Mbps", - maxHeight: 720, - bitrate: 4e6 - }), qualityOptions.push({ - name: "720p - 3 Mbps", - maxHeight: 720, - bitrate: 3e6 - }), qualityOptions.push({ - name: "720p - 2 Mbps", - maxHeight: 720, - bitrate: 2e6 - }), qualityOptions.push({ - name: "720p - 1.5 Mbps", - maxHeight: 720, - bitrate: 15e5 - }), qualityOptions.push({ - name: "720p - 1 Mbps", - maxHeight: 720, - bitrate: 1000001 - })), qualityOptions.push({ - name: "480p - 1 Mbps", - maxHeight: 480, - bitrate: 1e6 - }), qualityOptions.push({ - name: "480p - 720 kbps", - maxHeight: 480, - bitrate: 72e4 - }), qualityOptions.push({ - name: "480p - 420 kbps", - maxHeight: 480, - bitrate: 42e4 - }), qualityOptions.push({ - name: "360p", - maxHeight: 360, - bitrate: 4e5 - }), qualityOptions.push({ - name: "240p", - maxHeight: 240, - bitrate: 32e4 - }), qualityOptions.push({ - name: "144p", - maxHeight: 144, - bitrate: 192e3 - }); + + var maxStreamingBitrate = options.currentMaxBitrate; + var videoWidth = options.videoWidth; + + var maxAllowedWidth = videoWidth || 4096; + //var maxAllowedHeight = videoHeight || 2304; + + var qualityOptions = []; + + if (maxAllowedWidth >= 3800) { + qualityOptions.push({ name: '4K - 120 Mbps', maxHeight: 2160, bitrate: 120000000 }); + qualityOptions.push({ name: '4K - 100 Mbps', maxHeight: 2160, bitrate: 100000000 }); + qualityOptions.push({ name: '4K - 80 Mbps', maxHeight: 2160, bitrate: 80000000 }); + } + + // Some 1080- videos are reported as 1912? + if (maxAllowedWidth >= 1900) { + + qualityOptions.push({ name: '1080p - 60 Mbps', maxHeight: 1080, bitrate: 60000000 }); + qualityOptions.push({ name: '1080p - 50 Mbps', maxHeight: 1080, bitrate: 50000000 }); + qualityOptions.push({ name: '1080p - 40 Mbps', maxHeight: 1080, bitrate: 40000000 }); + qualityOptions.push({ name: '1080p - 30 Mbps', maxHeight: 1080, bitrate: 30000000 }); + qualityOptions.push({ name: '1080p - 25 Mbps', maxHeight: 1080, bitrate: 25000000 }); + qualityOptions.push({ name: '1080p - 20 Mbps', maxHeight: 1080, bitrate: 20000000 }); + qualityOptions.push({ name: '1080p - 15 Mbps', maxHeight: 1080, bitrate: 15000000 }); + qualityOptions.push({ name: '1080p - 10 Mbps', maxHeight: 1080, bitrate: 10000001 }); + qualityOptions.push({ name: '1080p - 8 Mbps', maxHeight: 1080, bitrate: 8000001 }); + qualityOptions.push({ name: '1080p - 6 Mbps', maxHeight: 1080, bitrate: 6000001 }); + qualityOptions.push({ name: '1080p - 5 Mbps', maxHeight: 1080, bitrate: 5000001 }); + qualityOptions.push({ name: '1080p - 4 Mbps', maxHeight: 1080, bitrate: 4000002 }); + + } else if (maxAllowedWidth >= 1260) { + qualityOptions.push({ name: '720p - 10 Mbps', maxHeight: 720, bitrate: 10000000 }); + qualityOptions.push({ name: '720p - 8 Mbps', maxHeight: 720, bitrate: 8000000 }); + qualityOptions.push({ name: '720p - 6 Mbps', maxHeight: 720, bitrate: 6000000 }); + qualityOptions.push({ name: '720p - 5 Mbps', maxHeight: 720, bitrate: 5000000 }); + + } else if (maxAllowedWidth >= 620) { + qualityOptions.push({ name: '480p - 4 Mbps', maxHeight: 480, bitrate: 4000001 }); + qualityOptions.push({ name: '480p - 3 Mbps', maxHeight: 480, bitrate: 3000001 }); + qualityOptions.push({ name: '480p - 2.5 Mbps', maxHeight: 480, bitrate: 2500000 }); + qualityOptions.push({ name: '480p - 2 Mbps', maxHeight: 480, bitrate: 2000001 }); + qualityOptions.push({ name: '480p - 1.5 Mbps', maxHeight: 480, bitrate: 1500001 }); + } + + if (maxAllowedWidth >= 1260) { + qualityOptions.push({ name: '720p - 4 Mbps', maxHeight: 720, bitrate: 4000000 }); + qualityOptions.push({ name: '720p - 3 Mbps', maxHeight: 720, bitrate: 3000000 }); + qualityOptions.push({ name: '720p - 2 Mbps', maxHeight: 720, bitrate: 2000000 }); + + // The extra 1 is because they're keyed off the bitrate value + qualityOptions.push({ name: '720p - 1.5 Mbps', maxHeight: 720, bitrate: 1500000 }); + qualityOptions.push({ name: '720p - 1 Mbps', maxHeight: 720, bitrate: 1000001 }); + } + + qualityOptions.push({ name: '480p - 1 Mbps', maxHeight: 480, bitrate: 1000000 }); + qualityOptions.push({ name: '480p - 720 kbps', maxHeight: 480, bitrate: 720000 }); + qualityOptions.push({ name: '480p - 420 kbps', maxHeight: 480, bitrate: 420000 }); + qualityOptions.push({ name: '360p', maxHeight: 360, bitrate: 400000 }); + qualityOptions.push({ name: '240p', maxHeight: 240, bitrate: 320000 }); + qualityOptions.push({ name: '144p', maxHeight: 144, bitrate: 192000 }); + var autoQualityOption = { - name: globalize.translate("sharedcomponents#Auto"), + name: globalize.translate('sharedcomponents#Auto'), bitrate: 0, selected: options.isAutomaticBitrateEnabled }; - if (options.enableAuto && qualityOptions.push(autoQualityOption), maxStreamingBitrate) { - for (var selectedIndex = -1, i = 0, length = qualityOptions.length; i < length; i++) { - var option = qualityOptions[i]; - 1 === selectedIndex && option.bitrate <= maxStreamingBitrate && (selectedIndex = i) - } - 1 === selectedIndex && (selectedIndex = qualityOptions.length - 1); - var currentQualityOption = qualityOptions[selectedIndex]; - options.isAutomaticBitrateEnabled ? autoQualityOption.autoText = currentQualityOption.name : currentQualityOption.selected = !0 + + if (options.enableAuto) { + qualityOptions.push(autoQualityOption); } - return qualityOptions + + if (maxStreamingBitrate) { + var selectedIndex = -1; + for (var i = 0, length = qualityOptions.length; i < length; i++) { + + var option = qualityOptions[i]; + + if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) { + selectedIndex = i; + } + } + + if (selectedIndex === -1) { + + selectedIndex = qualityOptions.length - 1; + } + + var currentQualityOption = qualityOptions[selectedIndex]; + + if (!options.isAutomaticBitrateEnabled) { + currentQualityOption.selected = true; + } else { + autoQualityOption.autoText = currentQualityOption.name; + } + } + + return qualityOptions; } function getAudioQualityOptions(options) { - var maxStreamingBitrate = options.currentMaxBitrate, - qualityOptions = []; - qualityOptions.push({ - name: "2 Mbps", - bitrate: 2e6 - }), qualityOptions.push({ - name: "1.5 Mbps", - bitrate: 15e5 - }), qualityOptions.push({ - name: "1 Mbps", - bitrate: 1e6 - }), qualityOptions.push({ - name: "320 kbps", - bitrate: 32e4 - }), qualityOptions.push({ - name: "256 kbps", - bitrate: 256e3 - }), qualityOptions.push({ - name: "192 kbps", - bitrate: 192e3 - }), qualityOptions.push({ - name: "128 kbps", - bitrate: 128e3 - }), qualityOptions.push({ - name: "96 kbps", - bitrate: 96e3 - }), qualityOptions.push({ - name: "64 kbps", - bitrate: 64e3 - }); + + var maxStreamingBitrate = options.currentMaxBitrate; + + var qualityOptions = []; + + qualityOptions.push({ name: '2 Mbps', bitrate: 2000000 }); + qualityOptions.push({ name: '1.5 Mbps', bitrate: 1500000 }); + qualityOptions.push({ name: '1 Mbps', bitrate: 1000000 }); + qualityOptions.push({ name: '320 kbps', bitrate: 320000 }); + qualityOptions.push({ name: '256 kbps', bitrate: 256000 }); + qualityOptions.push({ name: '192 kbps', bitrate: 192000 }); + qualityOptions.push({ name: '128 kbps', bitrate: 128000 }); + qualityOptions.push({ name: '96 kbps', bitrate: 96000 }); + qualityOptions.push({ name: '64 kbps', bitrate: 64000 }); + var autoQualityOption = { - name: globalize.translate("sharedcomponents#Auto"), + name: globalize.translate('sharedcomponents#Auto'), bitrate: 0, selected: options.isAutomaticBitrateEnabled }; - if (options.enableAuto && qualityOptions.push(autoQualityOption), maxStreamingBitrate) { - for (var selectedIndex = -1, i = 0, length = qualityOptions.length; i < length; i++) { - var option = qualityOptions[i]; - 1 === selectedIndex && option.bitrate <= maxStreamingBitrate && (selectedIndex = i) - } - 1 === selectedIndex && (selectedIndex = qualityOptions.length - 1); - var currentQualityOption = qualityOptions[selectedIndex]; - options.isAutomaticBitrateEnabled ? autoQualityOption.autoText = currentQualityOption.name : currentQualityOption.selected = !0 + + if (options.enableAuto) { + qualityOptions.push(autoQualityOption); } - return qualityOptions + + if (maxStreamingBitrate) { + var selectedIndex = -1; + for (var i = 0, length = qualityOptions.length; i < length; i++) { + + var option = qualityOptions[i]; + + if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) { + selectedIndex = i; + } + } + + if (selectedIndex === -1) { + + selectedIndex = qualityOptions.length - 1; + } + + var currentQualityOption = qualityOptions[selectedIndex]; + + if (!options.isAutomaticBitrateEnabled) { + currentQualityOption.selected = true; + } else { + autoQualityOption.autoText = currentQualityOption.name; + } + } + + return qualityOptions; } + return { getVideoQualityOptions: getVideoQualityOptions, getAudioQualityOptions: getAudioQualityOptions - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/recordingcreator/empty.png b/src/bower_components/emby-webcomponents/recordingcreator/empty.png index 34b25c436eca940c70f3000cbed29c05d3fb09af..0a91a7f8a19f8dd8e86819a031a1a0e3c85f7b9f 100644 GIT binary patch delta 138 zcmZ>n!#F{*o{fQlL0rIsj|=o#o)<`~!c0oCw&x;TbN egeNBe0g%hez}RK{7|38?@O1TaVOi&t&;$U*_9N5) delta 49 zcmbQk=rTc4n}vaaVXF)e6OiKeba4#fh)zyO0CJca81KBP^#HOMJYD@<);T3K0RZh; B3eNxl diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingbutton.js b/src/bower_components/emby-webcomponents/recordingcreator/recordingbutton.js index a5b085284c..93c4c13abc 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/recordingbutton.js +++ b/src/bower_components/emby-webcomponents/recordingcreator/recordingbutton.js @@ -1,60 +1,116 @@ -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"; +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 onRecordingButtonClick(e) { + var item = this.item; + if (item) { - var serverId = item.ServerId, - programId = item.Id, - timerId = item.TimerId, - timerStatus = item.Status, - seriesTimerId = item.SeriesTimerId, - instance = this; - recordingHelper.toggleRecording(serverId, programId, timerId, timerStatus, seriesTimerId).then(function() { - instance.refresh(serverId, programId) - }) + + var serverId = item.ServerId; + var programId = item.Id; + var timerId = item.TimerId; + var timerStatus = item.Status; + var seriesTimerId = item.SeriesTimerId; + + var instance = this; + + recordingHelper.toggleRecording(serverId, programId, timerId, timerStatus, seriesTimerId).then(function () { + instance.refresh(serverId, programId); + }); } } function RecordingButton(options) { - this.options = options, options.item ? this.refreshItem(options.item) : options.itemId && options.serverId && this.refresh(options.itemId, options.serverId); + this.options = options; + + if (options.item) { + this.refreshItem(options.item); + } else if (options.itemId && options.serverId) { + this.refresh(options.itemId, options.serverId); + } var button = options.button; - button.querySelector("i").innerHTML = ""; + button.querySelector('i').innerHTML = ''; + var clickFn = onRecordingButtonClick.bind(this); - this.clickFn = clickFn, dom.addEventListener(button, "click", clickFn, { - passive: !0 - }) + this.clickFn = clickFn; + + dom.addEventListener(button, 'click', clickFn, { + passive: true + }); } function getIndicatorIcon(item) { + var status; - if ("SeriesTimer" === item.Type) return ""; - if (item.TimerId || item.SeriesTimerId) status = item.Status || "Cancelled"; + + if (item.Type === 'SeriesTimer') { + return ''; + } + else if (item.TimerId || item.SeriesTimerId) { + + status = item.Status || 'Cancelled'; + } + else if (item.Type === 'Timer') { + + status = item.Status; + } else { - if ("Timer" !== item.Type) return ""; - status = item.Status + return ''; } - return item.SeriesTimerId && "Cancelled" !== status ? "" : "" + + if (item.SeriesTimerId) { + + if (status !== 'Cancelled') { + return ''; + } + } + + return ''; } - return RecordingButton.prototype.refresh = function(serverId, itemId) { - var apiClient = connectionManager.getApiClient(serverId), - self = this; - apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(item) { - self.refreshItem(item) - }) - }, RecordingButton.prototype.refreshItem = function(item) { - var options = this.options, - button = options.button; - this.item = item, button.querySelector("i").innerHTML = getIndicatorIcon(item), item.TimerId && "Cancelled" !== (item.Status || "Cancelled") ? button.classList.add("recordingIcon-active") : button.classList.remove("recordingIcon-active") - }, RecordingButton.prototype.destroy = function() { + + RecordingButton.prototype.refresh = function (serverId, itemId) { + + var apiClient = connectionManager.getApiClient(serverId); + var self = this; + apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { + self.refreshItem(item); + }); + }; + + RecordingButton.prototype.refreshItem = function (item) { + var options = this.options; - if (options) { - var button = options.button, - clickFn = this.clickFn; - clickFn && dom.removeEventListener(button, "click", clickFn, { - passive: !0 - }) + var button = options.button; + this.item = item; + button.querySelector('i').innerHTML = getIndicatorIcon(item); + + if (item.TimerId && (item.Status || 'Cancelled') !== 'Cancelled') { + button.classList.add('recordingIcon-active'); + } else { + button.classList.remove('recordingIcon-active'); } - this.options = null, this.item = null - }, RecordingButton + }; + + RecordingButton.prototype.destroy = function () { + + var options = this.options; + + if (options) { + var button = options.button; + + var clickFn = this.clickFn; + + if (clickFn) { + dom.removeEventListener(button, 'click', clickFn, { + passive: true + }); + } + } + + this.options = null; + this.item = null; + }; + + return RecordingButton; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.css b/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.css index 91d68b6019..dc1ba9b31a 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.css +++ b/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.css @@ -1,37 +1,27 @@ .recordingDialog-imageContainer { - -webkit-flex-shrink: 0; flex-shrink: 0; padding: 1em 1em 1em 0; - width: 25% + width: 25%; } .recordingDialog-img { - width: 100% + width: 100%; } .recordingDialog-itemName { - margin-top: .7em + margin-top: .7em; } .recordingDetailsContainer { - display: -webkit-box; - display: -webkit-flex; - display: flex + display: flex; } .recordingDetails { - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - flex-grow: 1 + flex-grow: 1; } .recordingDetailText { - display: -webkit-box; - display: -webkit-flex; display: flex; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-flex-wrap: wrap; - flex-wrap: wrap -} \ No newline at end of file + flex-wrap: wrap; +} diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.js b/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.js index 760cfdc3a9..2821946b6a 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.js +++ b/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.js @@ -1,95 +1,206 @@ -define(["dialogHelper", "globalize", "layoutManager", "mediaInfo", "apphost", "connectionManager", "require", "loading", "scrollHelper", "datetime", "imageLoader", "recordingFields", "events", "emby-checkbox", "emby-button", "emby-collapse", "emby-input", "paper-icon-button-light", "css!./../formdialog", "css!./recordingcreator", "material-icons"], function(dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, datetime, imageLoader, recordingFields, events) { - "use strict"; +define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'datetime', 'imageLoader', 'recordingFields', 'events', 'emby-checkbox', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, datetime, imageLoader, recordingFields, events) { + 'use strict'; + + var currentDialog; + var closeAction; + var currentRecordingFields; function closeDialog() { - dialogHelper.close(currentDialog) + + dialogHelper.close(currentDialog); } function init(context) { - context.querySelector(".btnPlay").addEventListener("click", function() { - closeAction = "play", closeDialog() - }), context.querySelector(".btnCancel").addEventListener("click", function() { - closeAction = null, closeDialog() - }) + + context.querySelector('.btnPlay').addEventListener('click', function () { + + closeAction = 'play'; + closeDialog(); + }); + + context.querySelector('.btnCancel').addEventListener('click', function () { + + closeAction = null; + closeDialog(); + }); } function getImageUrl(item, apiClient, imageHeight) { + var imageTags = item.ImageTags || {}; - return item.PrimaryImageTag && (imageTags.Primary = item.PrimaryImageTag), imageTags.Primary ? apiClient.getScaledImageUrl(item.Id, { - type: "Primary", - maxHeight: imageHeight, - tag: item.ImageTags.Primary - }) : imageTags.Thumb ? apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", - maxHeight: imageHeight, - tag: item.ImageTags.Thumb - }) : null + + if (item.PrimaryImageTag) { + imageTags.Primary = item.PrimaryImageTag; + } + + if (imageTags.Primary) { + + return apiClient.getScaledImageUrl(item.Id, { + type: "Primary", + maxHeight: imageHeight, + tag: item.ImageTags.Primary + }); + } + else if (imageTags.Thumb) { + + return apiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxHeight: imageHeight, + tag: item.ImageTags.Thumb + }); + } + + return null; } function renderRecording(context, defaultTimer, program, apiClient, refreshRecordingStateOnly) { + if (!refreshRecordingStateOnly) { - var imgUrl = getImageUrl(program, apiClient, 200), - imageContainer = context.querySelector(".recordingDialog-imageContainer"); - imgUrl ? (imageContainer.innerHTML = '', imageContainer.classList.remove("hide"), imageLoader.lazyChildren(imageContainer)) : (imageContainer.innerHTML = "", imageContainer.classList.add("hide")), context.querySelector(".recordingDialog-itemName").innerHTML = program.Name, context.querySelector(".formDialogHeaderTitle").innerHTML = program.Name, context.querySelector(".itemGenres").innerHTML = (program.Genres || []).join(" / "), context.querySelector(".itemOverview").innerHTML = program.Overview || ""; - var formDialogFooter = context.querySelector(".formDialogFooter"), - now = new Date; - now >= datetime.parseISO8601Date(program.StartDate, !0) && now < datetime.parseISO8601Date(program.EndDate, !0) ? formDialogFooter.classList.remove("hide") : formDialogFooter.classList.add("hide"), context.querySelector(".itemMiscInfoPrimary").innerHTML = mediaInfo.getPrimaryMediaInfoHtml(program) + var imgUrl = getImageUrl(program, apiClient, 200); + var imageContainer = context.querySelector('.recordingDialog-imageContainer'); + + if (imgUrl) { + imageContainer.innerHTML = ''; + imageContainer.classList.remove('hide'); + + imageLoader.lazyChildren(imageContainer); + } else { + imageContainer.innerHTML = ''; + imageContainer.classList.add('hide'); + } + + context.querySelector('.recordingDialog-itemName').innerHTML = program.Name; + context.querySelector('.formDialogHeaderTitle').innerHTML = program.Name; + context.querySelector('.itemGenres').innerHTML = (program.Genres || []).join(' / '); + context.querySelector('.itemOverview').innerHTML = program.Overview || ''; + + var formDialogFooter = context.querySelector('.formDialogFooter'); + var now = new Date(); + if (now >= datetime.parseISO8601Date(program.StartDate, true) && now < datetime.parseISO8601Date(program.EndDate, true)) { + formDialogFooter.classList.remove('hide'); + } else { + formDialogFooter.classList.add('hide'); + } + + context.querySelector('.itemMiscInfoPrimary').innerHTML = mediaInfo.getPrimaryMediaInfoHtml(program); } - context.querySelector(".itemMiscInfoSecondary").innerHTML = mediaInfo.getSecondaryMediaInfoHtml(program, {}), loading.hide() + + context.querySelector('.itemMiscInfoSecondary').innerHTML = mediaInfo.getSecondaryMediaInfoHtml(program, { + }); + + loading.hide(); } function reload(context, programId, serverId, refreshRecordingStateOnly) { + loading.show(); - var apiClient = connectionManager.getApiClient(serverId), - promise1 = apiClient.getNewLiveTvTimerDefaults({ - programId: programId - }), - promise2 = apiClient.getLiveTvProgram(programId, apiClient.getCurrentUserId()); - Promise.all([promise1, promise2]).then(function(responses) { - var defaults = responses[0], - program = responses[1]; - renderRecording(context, defaults, program, apiClient, refreshRecordingStateOnly) - }) + + var apiClient = connectionManager.getApiClient(serverId); + + var promise1 = apiClient.getNewLiveTvTimerDefaults({ programId: programId }); + var promise2 = apiClient.getLiveTvProgram(programId, apiClient.getCurrentUserId()); + + Promise.all([promise1, promise2]).then(function (responses) { + + var defaults = responses[0]; + var program = responses[1]; + + renderRecording(context, defaults, program, apiClient, refreshRecordingStateOnly); + }); } function executeCloseAction(action, programId, serverId) { - if ("play" === action) return void require(["playbackManager"], function(playbackManager) { - var apiClient = connectionManager.getApiClient(serverId); - apiClient.getLiveTvProgram(programId, apiClient.getCurrentUserId()).then(function(item) { - playbackManager.play({ - ids: [item.ChannelId], - serverId: serverId - }) - }) - }) + + if (action === 'play') { + + require(['playbackManager'], function (playbackManager) { + + var apiClient = connectionManager.getApiClient(serverId); + + apiClient.getLiveTvProgram(programId, apiClient.getCurrentUserId()).then(function (item) { + + playbackManager.play({ + ids: [item.ChannelId], + serverId: serverId + }); + }); + }); + return; + } } function showEditor(itemId, serverId) { - return new Promise(function(resolve, reject) { - closeAction = null, loading.show(), require(["text!./recordingcreator.template.html"], function(template) { - function onRecordingChanged() { - reload(dlg, itemId, serverId, !0) - } + + return new Promise(function (resolve, reject) { + + closeAction = null; + + loading.show(); + + require(['text!./recordingcreator.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'small'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.classList.add("recordingDialog"); - var html = ""; - html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, currentDialog = dlg, dlg.addEventListener("close", function() { - events.off(currentRecordingFields, "recordingchanged", onRecordingChanged), executeCloseAction(closeAction, itemId, serverId), currentRecordingFields && currentRecordingFields.hasChanged() ? resolve() : reject() - }), layoutManager.tv && scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1), init(dlg), reload(dlg, itemId, serverId), currentRecordingFields = new recordingFields({ - parent: dlg.querySelector(".recordingFields"), + + dlg.classList.add('formDialog'); + dlg.classList.add('recordingDialog'); + + var html = ''; + + html += globalize.translateDocument(template, 'sharedcomponents'); + + dlg.innerHTML = html; + + currentDialog = dlg; + + function onRecordingChanged() { + reload(dlg, itemId, serverId, true); + } + + dlg.addEventListener('close', function () { + + events.off(currentRecordingFields, 'recordingchanged', onRecordingChanged); + executeCloseAction(closeAction, itemId, serverId); + + if (currentRecordingFields && currentRecordingFields.hasChanged()) { + resolve(); + } else { + reject(); + } + }); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); + } + + init(dlg); + + reload(dlg, itemId, serverId); + + currentRecordingFields = new recordingFields({ + parent: dlg.querySelector('.recordingFields'), programId: itemId, serverId: serverId - }), events.on(currentRecordingFields, "recordingchanged", onRecordingChanged), dialogHelper.open(dlg) - }) - }) + }); + + events.on(currentRecordingFields, 'recordingchanged', onRecordingChanged); + + dialogHelper.open(dlg); + }); + }); } - var currentDialog, closeAction, currentRecordingFields; + return { show: showEditor - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingeditor.js b/src/bower_components/emby-webcomponents/recordingcreator/recordingeditor.js index bcc900e918..4082e56d27 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/recordingeditor.js +++ b/src/bower_components/emby-webcomponents/recordingcreator/recordingeditor.js @@ -1,73 +1,164 @@ -define(["dialogHelper", "globalize", "layoutManager", "mediaInfo", "apphost", "connectionManager", "require", "loading", "scrollHelper", "imageLoader", "scrollStyles", "emby-button", "emby-collapse", "emby-input", "paper-icon-button-light", "css!./../formdialog", "css!./recordingcreator", "material-icons", "flexStyles"], function(dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader) { - "use strict"; +define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'imageLoader', 'scrollStyles', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons', 'flexStyles'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader) { + 'use strict'; + + var currentDialog; + var recordingDeleted = false; + var currentItemId; + var currentServerId; + var currentResolve; function deleteTimer(apiClient, timerId) { - return new Promise(function(resolve, reject) { - require(["recordingHelper"], function(recordingHelper) { - recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject) - }) - }) + + return new Promise(function (resolve, reject) { + + require(['recordingHelper'], function (recordingHelper) { + + recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject); + }); + }); } function renderTimer(context, item, apiClient) { - item.ProgramInfo; - context.querySelector("#txtPrePaddingMinutes").value = item.PrePaddingSeconds / 60, context.querySelector("#txtPostPaddingMinutes").value = item.PostPaddingSeconds / 60, loading.hide() + + var program = item.ProgramInfo || {}; + + context.querySelector('#txtPrePaddingMinutes').value = item.PrePaddingSeconds / 60; + context.querySelector('#txtPostPaddingMinutes').value = item.PostPaddingSeconds / 60; + + loading.hide(); } function closeDialog(isDeleted) { - recordingDeleted = isDeleted, dialogHelper.close(currentDialog) + + recordingDeleted = isDeleted; + + dialogHelper.close(currentDialog); } function onSubmit(e) { - var form = this, - apiClient = connectionManager.getApiClient(currentServerId); - return apiClient.getLiveTvTimer(currentItemId).then(function(item) { - item.PrePaddingSeconds = 60 * form.querySelector("#txtPrePaddingMinutes").value, item.PostPaddingSeconds = 60 * form.querySelector("#txtPostPaddingMinutes").value, apiClient.updateLiveTvTimer(item).then(currentResolve) - }), e.preventDefault(), !1 + + var form = this; + + var apiClient = connectionManager.getApiClient(currentServerId); + + apiClient.getLiveTvTimer(currentItemId).then(function (item) { + item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60; + item.PostPaddingSeconds = form.querySelector('#txtPostPaddingMinutes').value * 60; + apiClient.updateLiveTvTimer(item).then(currentResolve); + }); + + e.preventDefault(); + + // Disable default form submission + return false; } function init(context) { - context.querySelector(".btnCancel").addEventListener("click", function() { - closeDialog(!1) - }), context.querySelector(".btnCancelRecording").addEventListener("click", function() { - deleteTimer(connectionManager.getApiClient(currentServerId), currentItemId).then(function() { - closeDialog(!0) - }) - }), context.querySelector("form").addEventListener("submit", onSubmit) + + context.querySelector('.btnCancel').addEventListener('click', function () { + + closeDialog(false); + }); + + context.querySelector('.btnCancelRecording').addEventListener('click', function () { + + var apiClient = connectionManager.getApiClient(currentServerId); + deleteTimer(apiClient, currentItemId).then(function () { + closeDialog(true); + }); + }); + + context.querySelector('form').addEventListener('submit', onSubmit); } function reload(context, id) { - loading.show(), currentItemId = id; + + loading.show(); + currentItemId = id; + var apiClient = connectionManager.getApiClient(currentServerId); - apiClient.getLiveTvTimer(id).then(function(result) { - renderTimer(context, result, apiClient), loading.hide() - }) + apiClient.getLiveTvTimer(id).then(function (result) { + + renderTimer(context, result, apiClient); + loading.hide(); + }); } function showEditor(itemId, serverId, options) { - return new Promise(function(resolve, reject) { - recordingDeleted = !1, currentServerId = serverId, loading.show(), options = options || {}, currentResolve = resolve, require(["text!./recordingeditor.template.html"], function(template) { + + return new Promise(function (resolve, reject) { + + recordingDeleted = false; + currentServerId = serverId; + loading.show(); + options = options || {}; + currentResolve = resolve; + + require(['text!./recordingeditor.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv && (dialogOptions.size = "fullscreen"); + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.classList.add("recordingDialog"), layoutManager.tv || (dlg.style["min-width"] = "20%", dlg.classList.add("dialog-fullscreen-lowres")); - var html = ""; - html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, !1 === options.enableCancel && dlg.querySelector(".formDialogFooter").classList.add("hide"), currentDialog = dlg, dlg.addEventListener("closing", function() { - recordingDeleted || dlg.querySelector(".btnSubmit").click() - }), dlg.addEventListener("close", function() { - recordingDeleted && resolve({ - updated: !0, - deleted: !0 - }) - }), layoutManager.tv && scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1), init(dlg), reload(dlg, itemId), dialogHelper.open(dlg) - }) - }) + + dlg.classList.add('formDialog'); + dlg.classList.add('recordingDialog'); + + if (!layoutManager.tv) { + dlg.style['min-width'] = '20%'; + dlg.classList.add('dialog-fullscreen-lowres'); + } + + var html = ''; + + html += globalize.translateDocument(template, 'sharedcomponents'); + + dlg.innerHTML = html; + + if (options.enableCancel === false) { + dlg.querySelector('.formDialogFooter').classList.add('hide'); + } + + currentDialog = dlg; + + dlg.addEventListener('closing', function () { + + if (!recordingDeleted) { + dlg.querySelector('.btnSubmit').click(); + } + }); + + dlg.addEventListener('close', function () { + + if (recordingDeleted) { + resolve({ + updated: true, + deleted: true + }); + } + }); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); + } + + init(dlg); + + reload(dlg, itemId); + + dialogHelper.open(dlg); + }); + }); } - var currentDialog, currentItemId, currentServerId, currentResolve, recordingDeleted = !1; + return { show: showEditor - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.css b/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.css index e48272d4a4..c8492f5298 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.css +++ b/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.css @@ -1,12 +1,12 @@ .recordingButton { margin-left: 0; - min-width: 10em + min-width: 10em; } .recordingIcon-active { - color: #c33 + color: #cc3333; } .recordSeriesContainer { - margin-bottom: .8em + margin-bottom: .8em; } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.js b/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.js index 735951b300..fd4b2c288a 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.js +++ b/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.js @@ -1,168 +1,362 @@ -define(["globalize", "connectionManager", "serverNotifications", "require", "loading", "apphost", "dom", "recordingHelper", "events", "registrationServices", "paper-icon-button-light", "emby-button", "css!./recordingfields", "flexStyles"], function(globalize, connectionManager, serverNotifications, require, loading, appHost, dom, recordingHelper, events, registrationServices) { - "use strict"; +define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'registrationServices', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields', 'flexStyles'], function (globalize, connectionManager, serverNotifications, require, loading, appHost, dom, recordingHelper, events, registrationServices) { + 'use strict'; function getRegistration(apiClient, feature) { + return registrationServices.validateFeature(feature, { - showDialog: !1, - viewOnly: !0 - }) + showDialog: false, + viewOnly: true + }); } function showConvertRecordingsUnlockMessage(context, apiClient) { - getRegistration(apiClient, getDvrFeatureCode()).then(function() { - context.querySelector(".convertRecordingsContainer").classList.add("hide") - }, function() { - context.querySelector(".convertRecordingsContainer").classList.remove("hide") - }) + + getRegistration(apiClient, getDvrFeatureCode()).then(function () { + + context.querySelector('.convertRecordingsContainer').classList.add('hide'); + }, function () { + context.querySelector('.convertRecordingsContainer').classList.remove('hide'); + }); } function showSeriesRecordingFields(context, programId, apiClient) { - getRegistration(apiClient, getDvrFeatureCode()).then(function() { - context.querySelector(".supporterContainer").classList.add("hide"), context.querySelector(".convertRecordingsContainer").classList.add("hide"), context.querySelector(".recordSeriesContainer").classList.remove("hide") - }, function() { - context.querySelector(".supporterContainerText").innerHTML = globalize.translate("sharedcomponents#MessageActiveSubscriptionRequiredSeriesRecordings"), context.querySelector(".supporterContainer").classList.remove("hide"), context.querySelector(".recordSeriesContainer").classList.add("hide"), context.querySelector(".convertRecordingsContainer").classList.add("hide") - }) + + getRegistration(apiClient, getDvrFeatureCode()).then(function () { + + context.querySelector('.supporterContainer').classList.add('hide'); + context.querySelector('.convertRecordingsContainer').classList.add('hide'); + context.querySelector('.recordSeriesContainer').classList.remove('hide'); + + }, function () { + + context.querySelector('.supporterContainerText').innerHTML = globalize.translate('sharedcomponents#MessageActiveSubscriptionRequiredSeriesRecordings'); + context.querySelector('.supporterContainer').classList.remove('hide'); + context.querySelector('.recordSeriesContainer').classList.add('hide'); + context.querySelector('.convertRecordingsContainer').classList.add('hide'); + }); } function getDvrFeatureCode() { - return "dvr" + + return 'dvr'; } function showSingleRecordingFields(context, programId, apiClient) { - getRegistration(apiClient, getDvrFeatureCode()).then(function() { - context.querySelector(".supporterContainer").classList.add("hide"), showConvertRecordingsUnlockMessage(context, apiClient) - }, function() { - context.querySelector(".supporterContainerText").innerHTML = globalize.translate("sharedcomponents#DvrSubscriptionRequired"), context.querySelector(".supporterContainer").classList.remove("hide"), context.querySelector(".convertRecordingsContainer").classList.add("hide") - }) + + getRegistration(apiClient, getDvrFeatureCode()).then(function () { + + context.querySelector('.supporterContainer').classList.add('hide'); + showConvertRecordingsUnlockMessage(context, apiClient); + + }, function () { + + context.querySelector('.supporterContainerText').innerHTML = globalize.translate('sharedcomponents#DvrSubscriptionRequired'); + context.querySelector('.supporterContainer').classList.remove('hide'); + context.querySelector('.convertRecordingsContainer').classList.add('hide'); + }); } function showRecordingFieldsContainer(context, programId, apiClient) { - getRegistration(apiClient, getDvrFeatureCode()).then(function() { - context.querySelector(".recordingFields").classList.remove("hide") - }, function() { - context.querySelector(".recordingFields").classList.add("hide") - }) + + getRegistration(apiClient, getDvrFeatureCode()).then(function () { + + context.querySelector('.recordingFields').classList.remove('hide'); + + }, function () { + + context.querySelector('.recordingFields').classList.add('hide'); + }); } function loadData(parent, program, apiClient) { - program.IsSeries ? (parent.querySelector(".recordSeriesContainer").classList.remove("hide"), showSeriesRecordingFields(parent, program.Id, apiClient)) : (parent.querySelector(".recordSeriesContainer").classList.add("hide"), showSingleRecordingFields(parent, program.Id, apiClient)), program.SeriesTimerId ? (parent.querySelector(".btnManageSeriesRecording").classList.remove("hide"), parent.querySelector(".seriesRecordingButton .recordingIcon").classList.add("recordingIcon-active"), parent.querySelector(".seriesRecordingButton .buttonText").innerHTML = globalize.translate("sharedcomponents#CancelSeries")) : (parent.querySelector(".btnManageSeriesRecording").classList.add("hide"), parent.querySelector(".seriesRecordingButton .recordingIcon").classList.remove("recordingIcon-active"), parent.querySelector(".seriesRecordingButton .buttonText").innerHTML = globalize.translate("sharedcomponents#RecordSeries")), program.TimerId && "Cancelled" !== program.Status ? (parent.querySelector(".btnManageRecording").classList.remove("hide"), parent.querySelector(".singleRecordingButton .recordingIcon").classList.add("recordingIcon-active"), "InProgress" === program.Status ? parent.querySelector(".singleRecordingButton .buttonText").innerHTML = globalize.translate("sharedcomponents#StopRecording") : parent.querySelector(".singleRecordingButton .buttonText").innerHTML = globalize.translate("sharedcomponents#DoNotRecord")) : (parent.querySelector(".btnManageRecording").classList.add("hide"), parent.querySelector(".singleRecordingButton .recordingIcon").classList.remove("recordingIcon-active"), parent.querySelector(".singleRecordingButton .buttonText").innerHTML = globalize.translate("sharedcomponents#Record")) + + if (program.IsSeries) { + parent.querySelector('.recordSeriesContainer').classList.remove('hide'); + showSeriesRecordingFields(parent, program.Id, apiClient); + } else { + parent.querySelector('.recordSeriesContainer').classList.add('hide'); + showSingleRecordingFields(parent, program.Id, apiClient); + } + + if (program.SeriesTimerId) { + 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('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('hide'); + parent.querySelector('.singleRecordingButton .recordingIcon').classList.add('recordingIcon-active'); + + if (program.Status === 'InProgress') { + parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#StopRecording'); + } else { + parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#DoNotRecord'); + } + + } else { + parent.querySelector('.btnManageRecording').classList.add('hide'); + parent.querySelector('.singleRecordingButton .recordingIcon').classList.remove('recordingIcon-active'); + parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#Record'); + } } function fetchData(instance) { - var options = instance.options, - apiClient = connectionManager.getApiClient(options.serverId); - return showRecordingFieldsContainer(options.parent, options.programId, apiClient), apiClient.getLiveTvProgram(options.programId, apiClient.getCurrentUserId()).then(function(program) { - instance.TimerId = program.TimerId, instance.Status = program.Status, instance.SeriesTimerId = program.SeriesTimerId, loadData(options.parent, program, apiClient) - }) + + var options = instance.options; + var apiClient = connectionManager.getApiClient(options.serverId); + + showRecordingFieldsContainer(options.parent, options.programId, apiClient); + + return apiClient.getLiveTvProgram(options.programId, apiClient.getCurrentUserId()).then(function (program) { + + instance.TimerId = program.TimerId; + instance.Status = program.Status; + instance.SeriesTimerId = program.SeriesTimerId; + + loadData(options.parent, program, apiClient); + }); } function onTimerChangedExternally(e, apiClient, data) { - var options = this.options, - refresh = !1; - data.Id && this.TimerId === data.Id && (refresh = !0), data.ProgramId && options && options.programId === data.ProgramId && (refresh = !0), refresh && this.refresh() + + var options = this.options; + var refresh = false; + + if (data.Id) { + if (this.TimerId === data.Id) { + refresh = true; + } + } + if (data.ProgramId && options) { + if (options.programId === data.ProgramId) { + refresh = true; + } + } + + if (refresh) { + this.refresh(); + } } function onSeriesTimerChangedExternally(e, apiClient, data) { - var options = this.options, - refresh = !1; - data.Id && this.SeriesTimerId === data.Id && (refresh = !0), data.ProgramId && options && options.programId === data.ProgramId && (refresh = !0), refresh && this.refresh() + + var options = this.options; + var refresh = false; + + if (data.Id) { + if (this.SeriesTimerId === data.Id) { + refresh = true; + } + } + if (data.ProgramId && options) { + if (options.programId === data.ProgramId) { + refresh = true; + } + } + + if (refresh) { + this.refresh(); + } } function RecordingEditor(options) { - this.options = options, this.embed(); + this.options = options; + this.embed(); + var timerChangedHandler = onTimerChangedExternally.bind(this); - this.timerChangedHandler = timerChangedHandler, events.on(serverNotifications, "TimerCreated", timerChangedHandler), events.on(serverNotifications, "TimerCancelled", timerChangedHandler); + this.timerChangedHandler = timerChangedHandler; + + events.on(serverNotifications, 'TimerCreated', timerChangedHandler); + events.on(serverNotifications, 'TimerCancelled', timerChangedHandler); + var seriesTimerChangedHandler = onSeriesTimerChangedExternally.bind(this); - this.seriesTimerChangedHandler = seriesTimerChangedHandler, events.on(serverNotifications, "SeriesTimerCreated", seriesTimerChangedHandler), events.on(serverNotifications, "SeriesTimerCancelled", seriesTimerChangedHandler) + this.seriesTimerChangedHandler = seriesTimerChangedHandler; + + events.on(serverNotifications, 'SeriesTimerCreated', seriesTimerChangedHandler); + events.on(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler); } function onSupporterButtonClick() { - registrationServices.showPremiereInfo() + registrationServices.showPremiereInfo(); } function onManageRecordingClick(e) { + var options = this.options; - if (this.TimerId && "Cancelled" !== this.Status) { - var self = this; - require(["recordingEditor"], function(recordingEditor) { - recordingEditor.show(self.TimerId, options.serverId, { - enableCancel: !1 - }).then(function() { - self.changed = !0 - }) - }) + + if (!this.TimerId || this.Status === 'Cancelled') { + return; } + + var self = this; + + require(['recordingEditor'], function (recordingEditor) { + + recordingEditor.show(self.TimerId, options.serverId, { + + enableCancel: false + + }).then(function () { + self.changed = true; + }); + }); } function onManageSeriesRecordingClick(e) { + var options = this.options; - if (this.SeriesTimerId) { - var self = this; - require(["seriesRecordingEditor"], function(seriesRecordingEditor) { - seriesRecordingEditor.show(self.SeriesTimerId, options.serverId, { - enableCancel: !1 - }).then(function() { - self.changed = !0 - }) - }) + + if (!this.SeriesTimerId) { + return; } + + var self = this; + + require(['seriesRecordingEditor'], function (seriesRecordingEditor) { + + seriesRecordingEditor.show(self.SeriesTimerId, options.serverId, { + + enableCancel: false + + }).then(function () { + self.changed = true; + }); + }); } function onRecordChange(e) { - this.changed = !0; - var self = this, - options = this.options, - apiClient = connectionManager.getApiClient(options.serverId), - button = dom.parentWithTag(e.target, "BUTTON"), - isChecked = !button.querySelector("i").classList.contains("recordingIcon-active"), - hasEnabledTimer = this.TimerId && "Cancelled" !== this.Status; - isChecked ? hasEnabledTimer || (loading.show(), recordingHelper.createRecording(apiClient, options.programId, !1).then(function() { - events.trigger(self, "recordingchanged"), fetchData(self), loading.hide() - })) : hasEnabledTimer && (loading.show(), recordingHelper.cancelTimer(apiClient, this.TimerId, !0).then(function() { - events.trigger(self, "recordingchanged"), fetchData(self), loading.hide() - })) + + this.changed = true; + + var self = this; + var options = this.options; + var apiClient = connectionManager.getApiClient(options.serverId); + + var button = dom.parentWithTag(e.target, 'BUTTON'); + var isChecked = !button.querySelector('i').classList.contains('recordingIcon-active'); + + var hasEnabledTimer = this.TimerId && this.Status !== 'Cancelled'; + + if (isChecked) { + if (!hasEnabledTimer) { + loading.show(); + recordingHelper.createRecording(apiClient, options.programId, false).then(function () { + events.trigger(self, 'recordingchanged'); + fetchData(self); + loading.hide(); + }); + } + } else { + if (hasEnabledTimer) { + loading.show(); + recordingHelper.cancelTimer(apiClient, this.TimerId, true).then(function () { + events.trigger(self, 'recordingchanged'); + fetchData(self); + loading.hide(); + }); + } + } } function sendToast(msg) { - require(["toast"], function(toast) { - toast(msg) - }) + require(['toast'], function (toast) { + toast(msg); + }); } function onRecordSeriesChange(e) { - this.changed = !0; - var self = this, - options = this.options, - apiClient = connectionManager.getApiClient(options.serverId); - if (dom.parentWithTag(e.target, "BUTTON").querySelector("i").classList.contains("recordingIcon-active")) showSingleRecordingFields(options.parent, options.programId, apiClient), this.SeriesTimerId && apiClient.cancelLiveTvSeriesTimer(this.SeriesTimerId).then(function() { - sendToast(globalize.translate("sharedcomponents#RecordingCancelled")), fetchData(self) - }); - else if (showSeriesRecordingFields(options.parent, options.programId, apiClient), !this.SeriesTimerId) { - var promise = this.TimerId ? recordingHelper.changeRecordingToSeries(apiClient, this.TimerId, options.programId) : recordingHelper.createRecording(apiClient, options.programId, !0); - promise.then(function() { - fetchData(self) - }) + + this.changed = true; + + var self = this; + var options = this.options; + var apiClient = connectionManager.getApiClient(options.serverId); + + var button = dom.parentWithTag(e.target, 'BUTTON'); + var isChecked = !button.querySelector('i').classList.contains('recordingIcon-active'); + + if (isChecked) { + showSeriesRecordingFields(options.parent, options.programId, apiClient); + + if (!this.SeriesTimerId) { + + var promise = this.TimerId ? + recordingHelper.changeRecordingToSeries(apiClient, this.TimerId, options.programId) : + recordingHelper.createRecording(apiClient, options.programId, true); + + promise.then(function () { + fetchData(self); + }); + } + } else { + + showSingleRecordingFields(options.parent, options.programId, apiClient); + + if (this.SeriesTimerId) { + apiClient.cancelLiveTvSeriesTimer(this.SeriesTimerId).then(function () { + sendToast(globalize.translate('sharedcomponents#RecordingCancelled')); + fetchData(self); + }); + } } } - return RecordingEditor.prototype.embed = function() { + + RecordingEditor.prototype.embed = function () { + var self = this; - return new Promise(function(resolve, reject) { - require(["text!./recordingfields.template.html"], function(template) { - var options = self.options, - context = options.parent; - context.innerHTML = globalize.translateDocument(template, "sharedcomponents"); - for (var supporterButtons = context.querySelectorAll(".btnSupporter"), i = 0, length = supporterButtons.length; i < length; i++) supporterButtons[i].addEventListener("click", onSupporterButtonClick); - context.querySelector(".singleRecordingButton").addEventListener("click", onRecordChange.bind(self)), context.querySelector(".seriesRecordingButton").addEventListener("click", onRecordSeriesChange.bind(self)), context.querySelector(".btnManageRecording").addEventListener("click", onManageRecordingClick.bind(self)), context.querySelector(".btnManageSeriesRecording").addEventListener("click", onManageSeriesRecordingClick.bind(self)), fetchData(self).then(resolve) - }) - }) - }, RecordingEditor.prototype.hasChanged = function() { - return this.changed - }, RecordingEditor.prototype.refresh = function() { - fetchData(this) - }, RecordingEditor.prototype.destroy = function() { + + return new Promise(function (resolve, reject) { + + require(['text!./recordingfields.template.html'], function (template) { + + var options = self.options; + var context = options.parent; + context.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + var supporterButtons = context.querySelectorAll('.btnSupporter'); + for (var i = 0, length = supporterButtons.length; i < length; i++) { + supporterButtons[i].addEventListener('click', onSupporterButtonClick); + } + + context.querySelector('.singleRecordingButton').addEventListener('click', onRecordChange.bind(self)); + context.querySelector('.seriesRecordingButton').addEventListener('click', onRecordSeriesChange.bind(self)); + context.querySelector('.btnManageRecording').addEventListener('click', onManageRecordingClick.bind(self)); + context.querySelector('.btnManageSeriesRecording').addEventListener('click', onManageSeriesRecordingClick.bind(self)); + + fetchData(self).then(resolve); + }); + }); + }; + + RecordingEditor.prototype.hasChanged = function () { + + return this.changed; + }; + + RecordingEditor.prototype.refresh = function () { + + fetchData(this); + }; + + RecordingEditor.prototype.destroy = function () { + var timerChangedHandler = this.timerChangedHandler; - this.timerChangedHandler = null, events.off(serverNotifications, "TimerCreated", timerChangedHandler), events.off(serverNotifications, "TimerCancelled", timerChangedHandler); + this.timerChangedHandler = null; + + events.off(serverNotifications, 'TimerCreated', timerChangedHandler); + events.off(serverNotifications, 'TimerCancelled', timerChangedHandler); + var seriesTimerChangedHandler = this.seriesTimerChangedHandler; - this.seriesTimerChangedHandler = null, events.off(serverNotifications, "SeriesTimerCreated", seriesTimerChangedHandler), events.off(serverNotifications, "SeriesTimerCancelled", seriesTimerChangedHandler) - }, RecordingEditor + this.seriesTimerChangedHandler = null; + + events.off(serverNotifications, 'SeriesTimerCreated', seriesTimerChangedHandler); + events.off(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler); + }; + + return RecordingEditor; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordinghelper.js b/src/bower_components/emby-webcomponents/recordingcreator/recordinghelper.js index 6839b3ea3c..363111a9a9 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/recordinghelper.js +++ b/src/bower_components/emby-webcomponents/recordingcreator/recordinghelper.js @@ -1,116 +1,221 @@ -define(["globalize", "loading", "connectionManager", "registrationServices"], function(globalize, loading, connectionManager, registrationServices) { - "use strict"; +define(['globalize', 'loading', 'connectionManager', 'registrationServices'], function (globalize, loading, connectionManager, registrationServices) { + 'use strict'; function changeRecordingToSeries(apiClient, timerId, programId, confirmTimerCancellation) { - return loading.show(), apiClient.getItem(apiClient.getCurrentUserId(), programId).then(function(item) { - return item.IsSeries ? apiClient.getNewLiveTvTimerDefaults({ - programId: programId - }).then(function(timerDefaults) { - return apiClient.createLiveTvSeriesTimer(timerDefaults).then(function() { - loading.hide(), sendToast(globalize.translate("sharedcomponents#SeriesRecordingScheduled")) - }) - }) : confirmTimerCancellation ? cancelTimerWithConfirmation(timerId, apiClient.serverId()) : cancelTimer(apiClient.serverId(), timerId, !0) - }) + + loading.show(); + + return apiClient.getItem(apiClient.getCurrentUserId(), programId).then(function (item) { + + if (item.IsSeries) { + // create series + return apiClient.getNewLiveTvTimerDefaults({ programId: programId }).then(function (timerDefaults) { + + return apiClient.createLiveTvSeriesTimer(timerDefaults).then(function () { + + loading.hide(); + sendToast(globalize.translate('sharedcomponents#SeriesRecordingScheduled')); + }); + }); + } else { + // cancel + if (confirmTimerCancellation) { + return cancelTimerWithConfirmation(timerId, apiClient.serverId()); + } + + return cancelTimer(apiClient.serverId(), timerId, true); + } + }); } function cancelTimerWithConfirmation(timerId, serverId) { - return new Promise(function(resolve, reject) { - require(["confirm"], function(confirm) { + + return new Promise(function (resolve, reject) { + + require(['confirm'], function (confirm) { + confirm({ - text: globalize.translate("sharedcomponents#MessageConfirmRecordingCancellation"), - primary: "cancel", - confirmText: globalize.translate("sharedcomponents#HeaderCancelRecording"), - cancelText: globalize.translate("sharedcomponents#HeaderKeepRecording") - }).then(function() { - loading.show(), cancelTimer(connectionManager.getApiClient(serverId), timerId, !0).then(resolve, reject) - }, reject) - }) - }) + + text: globalize.translate('sharedcomponents#MessageConfirmRecordingCancellation'), + primary: 'cancel', + confirmText: globalize.translate('sharedcomponents#HeaderCancelRecording'), + cancelText: globalize.translate('sharedcomponents#HeaderKeepRecording') + + }).then(function () { + + loading.show(); + + var apiClient = connectionManager.getApiClient(serverId); + cancelTimer(apiClient, timerId, true).then(resolve, reject); + + }, reject); + }); + }); } function cancelSeriesTimerWithConfirmation(timerId, serverId) { - return new Promise(function(resolve, reject) { - require(["confirm"], function(confirm) { + + return new Promise(function (resolve, reject) { + + require(['confirm'], function (confirm) { + confirm({ - text: globalize.translate("sharedcomponents#MessageConfirmRecordingCancellation"), - primary: "cancel", - confirmText: globalize.translate("sharedcomponents#HeaderCancelSeries"), - cancelText: globalize.translate("sharedcomponents#HeaderKeepSeries") - }).then(function() { - loading.show(), connectionManager.getApiClient(serverId).cancelLiveTvSeriesTimer(timerId).then(function() { - require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#SeriesCancelled")) - }), loading.hide(), resolve() - }, reject) - }, reject) - }) - }) + + text: globalize.translate('sharedcomponents#MessageConfirmRecordingCancellation'), + primary: 'cancel', + confirmText: globalize.translate('sharedcomponents#HeaderCancelSeries'), + cancelText: globalize.translate('sharedcomponents#HeaderKeepSeries') + + }).then(function () { + + loading.show(); + + var apiClient = connectionManager.getApiClient(serverId); + apiClient.cancelLiveTvSeriesTimer(timerId).then(function () { + + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#SeriesCancelled')); + }); + + loading.hide(); + resolve(); + }, reject); + + }, reject); + }); + }); } function cancelTimer(apiClient, timerId, hideLoading) { - return loading.show(), apiClient.cancelLiveTvTimer(timerId).then(function() { - !1 !== hideLoading && (loading.hide(), sendToast(globalize.translate("sharedcomponents#RecordingCancelled"))) - }) + loading.show(); + return apiClient.cancelLiveTvTimer(timerId).then(function () { + + if (hideLoading !== false) { + loading.hide(); + sendToast(globalize.translate('sharedcomponents#RecordingCancelled')); + } + }); } function createRecording(apiClient, programId, isSeries) { - return loading.show(), apiClient.getNewLiveTvTimerDefaults({ - programId: programId - }).then(function(item) { - return (isSeries ? apiClient.createLiveTvSeriesTimer(item) : apiClient.createLiveTvTimer(item)).then(function() { - loading.hide(), sendToast(globalize.translate("sharedcomponents#RecordingScheduled")) - }) - }) + + loading.show(); + return apiClient.getNewLiveTvTimerDefaults({ programId: programId }).then(function (item) { + + var promise = isSeries ? + apiClient.createLiveTvSeriesTimer(item) : + apiClient.createLiveTvTimer(item); + + return promise.then(function () { + + loading.hide(); + sendToast(globalize.translate('sharedcomponents#RecordingScheduled')); + }); + }); } function sendToast(msg) { - require(["toast"], function(toast) { - toast(msg) - }) + require(['toast'], function (toast) { + toast(msg); + }); } function showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId) { - return new Promise(function(resolve, reject) { - require(["dialog"], function(dialog) { + return new Promise(function (resolve, reject) { + + require(['dialog'], function (dialog) { + var items = []; + items.push({ - name: globalize.translate("sharedcomponents#HeaderKeepRecording"), - id: "cancel", - type: "submit" - }), "InProgress" === timerStatus ? items.push({ - name: globalize.translate("sharedcomponents#HeaderStopRecording"), - id: "canceltimer", - type: "cancel" - }) : items.push({ - name: globalize.translate("sharedcomponents#HeaderCancelRecording"), - id: "canceltimer", - type: "cancel" - }), items.push({ - name: globalize.translate("sharedcomponents#HeaderCancelSeries"), - id: "cancelseriestimer", - type: "cancel" - }), dialog({ - text: globalize.translate("sharedcomponents#MessageConfirmRecordingCancellation"), + name: globalize.translate('sharedcomponents#HeaderKeepRecording'), + id: 'cancel', + type: 'submit' + }); + + if (timerStatus === 'InProgress') { + items.push({ + name: globalize.translate('sharedcomponents#HeaderStopRecording'), + id: 'canceltimer', + type: 'cancel' + }); + } else { + items.push({ + name: globalize.translate('sharedcomponents#HeaderCancelRecording'), + id: 'canceltimer', + type: 'cancel' + }); + } + + items.push({ + name: globalize.translate('sharedcomponents#HeaderCancelSeries'), + id: 'cancelseriestimer', + type: 'cancel' + }); + + dialog({ + + text: globalize.translate('sharedcomponents#MessageConfirmRecordingCancellation'), buttons: items - }).then(function(result) { + + }).then(function (result) { + var apiClient = connectionManager.getApiClient(serverId); - "canceltimer" === result ? (loading.show(), cancelTimer(apiClient, timerId, !0).then(resolve, reject)) : "cancelseriestimer" === result ? (loading.show(), apiClient.cancelLiveTvSeriesTimer(seriesTimerId).then(function() { - require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#SeriesCancelled")) - }), loading.hide(), resolve() - }, reject)) : resolve() - }, reject) - }) - }) + + if (result === 'canceltimer') { + loading.show(); + + cancelTimer(apiClient, timerId, true).then(resolve, reject); + } + else if (result === 'cancelseriestimer') { + + loading.show(); + + apiClient.cancelLiveTvSeriesTimer(seriesTimerId).then(function () { + + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#SeriesCancelled')); + }); + + loading.hide(); + resolve(); + }, reject); + } else { + resolve(); + } + + }, reject); + }); + }); } function toggleRecording(serverId, programId, timerId, timerStatus, seriesTimerId) { - return registrationServices.validateFeature("dvr").then(function() { - var apiClient = connectionManager.getApiClient(serverId), - hasTimer = timerId && "Cancelled" !== timerStatus; - return seriesTimerId && hasTimer ? showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId) : hasTimer && programId ? changeRecordingToSeries(apiClient, timerId, programId, !0) : programId ? createRecording(apiClient, programId) : Promise.reject() - }) + + return registrationServices.validateFeature('dvr').then(function () { + var apiClient = connectionManager.getApiClient(serverId); + + var hasTimer = timerId && timerStatus !== 'Cancelled'; + + if (seriesTimerId && hasTimer) { + + // cancel + return showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId); + + } else if (hasTimer && programId) { + + // change to series recording, if possible + // otherwise cancel individual recording + return changeRecordingToSeries(apiClient, timerId, programId, true); + + } else if (programId) { + // schedule recording + return createRecording(apiClient, programId); + } else { + return Promise.reject(); + } + }); } + return { cancelTimer: cancelTimer, createRecording: createRecording, @@ -118,5 +223,5 @@ define(["globalize", "loading", "connectionManager", "registrationServices"], fu toggleRecording: toggleRecording, cancelTimerWithConfirmation: cancelTimerWithConfirmation, cancelSeriesTimerWithConfirmation: cancelSeriesTimerWithConfirmation - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/recordingcreator/seriesrecordingeditor.js b/src/bower_components/emby-webcomponents/recordingcreator/seriesrecordingeditor.js index 38b1a49652..bb92877fc4 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/seriesrecordingeditor.js +++ b/src/bower_components/emby-webcomponents/recordingcreator/seriesrecordingeditor.js @@ -1,98 +1,270 @@ -define(["dialogHelper", "globalize", "layoutManager", "mediaInfo", "apphost", "connectionManager", "require", "loading", "scrollHelper", "imageLoader", "datetime", "scrollStyles", "emby-button", "emby-checkbox", "emby-input", "emby-select", "paper-icon-button-light", "css!./../formdialog", "css!./recordingcreator", "material-icons", "flexStyles"], function(dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader, datetime) { - "use strict"; +define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'imageLoader', 'datetime', 'scrollStyles', 'emby-button', 'emby-checkbox', 'emby-input', 'emby-select', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons', 'flexStyles'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader, datetime) { + 'use strict'; + + var currentDialog; + var recordingUpdated = false; + var recordingDeleted = false; + var currentItemId; + var currentServerId; function deleteTimer(apiClient, timerId) { - return new Promise(function(resolve, reject) { - require(["recordingHelper"], function(recordingHelper) { - recordingHelper.cancelSeriesTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject) - }) - }) + + return new Promise(function (resolve, reject) { + + require(['recordingHelper'], function (recordingHelper) { + + recordingHelper.cancelSeriesTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject); + }); + }); } function renderTimer(context, item, apiClient) { - item.ProgramInfo; - context.querySelector("#txtPrePaddingMinutes").value = item.PrePaddingSeconds / 60, context.querySelector("#txtPostPaddingMinutes").value = item.PostPaddingSeconds / 60, context.querySelector(".selectChannels").value = item.RecordAnyChannel ? "all" : "one", context.querySelector(".selectAirTime").value = item.RecordAnyTime ? "any" : "original", context.querySelector(".selectShowType").value = item.RecordNewOnly ? "new" : "all", context.querySelector(".chkSkipEpisodesInLibrary").checked = item.SkipEpisodesInLibrary, context.querySelector(".selectKeepUpTo").value = item.KeepUpTo || 0, item.ChannelName || item.ChannelNumber ? context.querySelector(".optionChannelOnly").innerHTML = globalize.translate("sharedcomponents#ChannelNameOnly", item.ChannelName || item.ChannelNumber) : context.querySelector(".optionChannelOnly").innerHTML = globalize.translate("sharedcomponents#OneChannel"), context.querySelector(".optionAroundTime").innerHTML = globalize.translate("sharedcomponents#AroundTime", datetime.getDisplayTime(datetime.parseISO8601Date(item.StartDate))), loading.hide() + + var program = item.ProgramInfo || {}; + + context.querySelector('#txtPrePaddingMinutes').value = item.PrePaddingSeconds / 60; + context.querySelector('#txtPostPaddingMinutes').value = item.PostPaddingSeconds / 60; + + context.querySelector('.selectChannels').value = item.RecordAnyChannel ? 'all' : 'one'; + context.querySelector('.selectAirTime').value = item.RecordAnyTime ? 'any' : 'original'; + + context.querySelector('.selectShowType').value = item.RecordNewOnly ? 'new' : 'all'; + context.querySelector('.chkSkipEpisodesInLibrary').checked = item.SkipEpisodesInLibrary; + context.querySelector('.selectKeepUpTo').value = item.KeepUpTo || 0; + + if (item.ChannelName || item.ChannelNumber) { + context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('sharedcomponents#ChannelNameOnly', item.ChannelName || item.ChannelNumber); + } else { + context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('sharedcomponents#OneChannel'); + } + + context.querySelector('.optionAroundTime').innerHTML = globalize.translate('sharedcomponents#AroundTime', datetime.getDisplayTime(datetime.parseISO8601Date(item.StartDate))); + + loading.hide(); } function closeDialog(isDeleted) { - recordingUpdated = !0, recordingDeleted = isDeleted, dialogHelper.close(currentDialog) + + recordingUpdated = true; + recordingDeleted = isDeleted; + + dialogHelper.close(currentDialog); } function onSubmit(e) { - var form = this, - apiClient = connectionManager.getApiClient(currentServerId); - return apiClient.getLiveTvSeriesTimer(currentItemId).then(function(item) { - item.PrePaddingSeconds = 60 * form.querySelector("#txtPrePaddingMinutes").value, item.PostPaddingSeconds = 60 * form.querySelector("#txtPostPaddingMinutes").value, item.RecordAnyChannel = "all" === form.querySelector(".selectChannels").value, item.RecordAnyTime = "any" === form.querySelector(".selectAirTime").value, item.RecordNewOnly = "new" === form.querySelector(".selectShowType").value, item.SkipEpisodesInLibrary = form.querySelector(".chkSkipEpisodesInLibrary").checked, item.KeepUpTo = form.querySelector(".selectKeepUpTo").value, apiClient.updateLiveTvSeriesTimer(item) - }), e.preventDefault(), !1 + + var form = this; + + var apiClient = connectionManager.getApiClient(currentServerId); + + apiClient.getLiveTvSeriesTimer(currentItemId).then(function (item) { + + item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60; + item.PostPaddingSeconds = form.querySelector('#txtPostPaddingMinutes').value * 60; + item.RecordAnyChannel = form.querySelector('.selectChannels').value === 'all'; + item.RecordAnyTime = form.querySelector('.selectAirTime').value === 'any'; + item.RecordNewOnly = form.querySelector('.selectShowType').value === 'new'; + item.SkipEpisodesInLibrary = form.querySelector('.chkSkipEpisodesInLibrary').checked; + item.KeepUpTo = form.querySelector('.selectKeepUpTo').value; + + apiClient.updateLiveTvSeriesTimer(item); + }); + + e.preventDefault(); + + // Disable default form submission + return false; } function init(context) { - fillKeepUpTo(context), context.querySelector(".btnCancel").addEventListener("click", function() { - closeDialog(!1) - }), context.querySelector(".btnCancelRecording").addEventListener("click", function() { - deleteTimer(connectionManager.getApiClient(currentServerId), currentItemId).then(function() { - closeDialog(!0) - }) - }), context.querySelector("form").addEventListener("submit", onSubmit) + + fillKeepUpTo(context); + + context.querySelector('.btnCancel').addEventListener('click', function () { + + closeDialog(false); + }); + + context.querySelector('.btnCancelRecording').addEventListener('click', function () { + + var apiClient = connectionManager.getApiClient(currentServerId); + deleteTimer(apiClient, currentItemId).then(function () { + closeDialog(true); + }); + }); + + context.querySelector('form').addEventListener('submit', onSubmit); } function reload(context, id) { + var apiClient = connectionManager.getApiClient(currentServerId); - loading.show(), "string" == typeof id ? (currentItemId = id, apiClient.getLiveTvSeriesTimer(id).then(function(result) { - renderTimer(context, result, apiClient), loading.hide() - })) : id && (currentItemId = id.Id, renderTimer(context, id, apiClient), loading.hide()) + + 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) { - for (var html = "", i = 0; i <= 50; i++) { - var text; - text = 0 === i ? globalize.translate("sharedcomponents#AsManyAsPossible") : 1 === i ? globalize.translate("sharedcomponents#ValueOneEpisode") : globalize.translate("sharedcomponents#ValueEpisodeCount", i), html += '" - } - context.querySelector(".selectKeepUpTo").innerHTML = html - } + var html = ''; + + for (var i = 0; i <= 50; i++) { + + var text; + + if (i === 0) { + text = globalize.translate('sharedcomponents#AsManyAsPossible'); + } else if (i === 1) { + text = globalize.translate('sharedcomponents#ValueOneEpisode'); + } else { + text = globalize.translate('sharedcomponents#ValueEpisodeCount', i); + } + + html += ''; + } + + context.querySelector('.selectKeepUpTo').innerHTML = html; + } + function onFieldChange(e) { - this.querySelector(".btnSubmit").click() + this.querySelector('.btnSubmit').click(); } function embed(itemId, serverId, options) { - recordingUpdated = !1, recordingDeleted = !1, currentServerId = serverId, loading.show(), options = options || {}, require(["text!./seriesrecordingeditor.template.html"], function(template) { + + recordingUpdated = false; + recordingDeleted = false; + currentServerId = serverId; + loading.show(); + options = options || {}; + + require(['text!./seriesrecordingeditor.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'small'; + } + var dlg = options.context; - dlg.classList.add("hide"), dlg.innerHTML = globalize.translateDocument(template, "sharedcomponents"), dlg.querySelector(".formDialogHeader").classList.add("hide"), dlg.querySelector(".formDialogFooter").classList.add("hide"), dlg.querySelector(".formDialogContent").className = "", dlg.querySelector(".dialogContentInner").className = "", dlg.classList.remove("hide"), dlg.removeEventListener("change", onFieldChange), dlg.addEventListener("change", onFieldChange), currentDialog = dlg, init(dlg), reload(dlg, itemId) - }) + + dlg.classList.add('hide'); + dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + dlg.querySelector('.formDialogHeader').classList.add('hide'); + dlg.querySelector('.formDialogFooter').classList.add('hide'); + dlg.querySelector('.formDialogContent').className = ''; + dlg.querySelector('.dialogContentInner').className = ''; + dlg.classList.remove('hide'); + + dlg.removeEventListener('change', onFieldChange); + dlg.addEventListener('change', onFieldChange); + + currentDialog = dlg; + + init(dlg); + + reload(dlg, itemId); + }); } function showEditor(itemId, serverId, options) { - return new Promise(function(resolve, reject) { - recordingUpdated = !1, recordingDeleted = !1, currentServerId = serverId, loading.show(), options = options || {}, require(["text!./seriesrecordingeditor.template.html"], function(template) { + + return new Promise(function (resolve, reject) { + + recordingUpdated = false; + recordingDeleted = false; + currentServerId = serverId; + loading.show(); + options = options || {}; + + require(['text!./seriesrecordingeditor.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'small'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.classList.add("recordingDialog"), layoutManager.tv || (dlg.style["min-width"] = "20%"); - var html = ""; - html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, !1 === options.enableCancel && dlg.querySelector(".formDialogFooter").classList.add("hide"), currentDialog = dlg, dlg.addEventListener("closing", function() { - recordingDeleted || this.querySelector(".btnSubmit").click() - }), dlg.addEventListener("close", function() { - recordingUpdated ? resolve({ - updated: !0, - deleted: recordingDeleted - }) : reject() - }), layoutManager.tv && scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1), init(dlg), reload(dlg, itemId), dialogHelper.open(dlg) - }) - }) + + dlg.classList.add('formDialog'); + dlg.classList.add('recordingDialog'); + + if (!layoutManager.tv) { + dlg.style['min-width'] = '20%'; + } + + var html = ''; + + html += globalize.translateDocument(template, 'sharedcomponents'); + + dlg.innerHTML = html; + + if (options.enableCancel === false) { + dlg.querySelector('.formDialogFooter').classList.add('hide'); + } + + currentDialog = dlg; + + dlg.addEventListener('closing', function () { + + if (!recordingDeleted) { + this.querySelector('.btnSubmit').click(); + } + }); + + dlg.addEventListener('close', function () { + + if (recordingUpdated) { + resolve({ + updated: true, + deleted: recordingDeleted + }); + } else { + reject(); + } + }); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); + } + + init(dlg); + + reload(dlg, itemId); + + dialogHelper.open(dlg); + }); + }); } - var currentDialog, currentItemId, currentServerId, recordingUpdated = !1, - recordingDeleted = !1; + return { show: showEditor, embed: embed - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/refreshdialog/refreshdialog.js b/src/bower_components/emby-webcomponents/refreshdialog/refreshdialog.js index 1b35092781..2165960d78 100644 --- a/src/bower_components/emby-webcomponents/refreshdialog/refreshdialog.js +++ b/src/bower_components/emby-webcomponents/refreshdialog/refreshdialog.js @@ -1,65 +1,175 @@ -define(["shell", "dialogHelper", "loading", "layoutManager", "connectionManager", "appRouter", "globalize", "emby-input", "emby-checkbox", "paper-icon-button-light", "emby-select", "material-icons", "css!./../formdialog", "emby-button"], function(shell, dialogHelper, loading, layoutManager, connectionManager, appRouter, globalize) { - "use strict"; +define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-input', 'emby-checkbox', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button'], function (shell, dialogHelper, loading, layoutManager, connectionManager, appRouter, globalize) { + 'use strict'; function parentWithClass(elem, className) { - for (; !elem.classList || !elem.classList.contains(className);) - if (!(elem = elem.parentNode)) return null; - return elem + + while (!elem.classList || !elem.classList.contains(className)) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; } function getEditorHtml() { - var html = ""; - return html += '
', html += '
', html += '
', html += '
', html += '", html += "
", html += '", html += '
', html += globalize.translate("sharedcomponents#RefreshDialogHelp"), html += "
", html += '', html += "
", html += '
', html += '", html += "
", html += "
", html += "
", html += "
" + + var html = ''; + + html += '
'; + html += '
'; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + + html += ''; + + html += '
'; + html += globalize.translate('sharedcomponents#RefreshDialogHelp'); + html += '
'; + + html += ''; + + html += '
'; + html += '
'; + html += ''; + html += '
'; + + html += '
'; + html += '
'; + html += '
'; + + return html; } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function onSubmit(e) { + loading.show(); - var instance = this, - dlg = parentWithClass(e.target, "dialog"), - options = instance.options, - apiClient = connectionManager.getApiClient(options.serverId), - replaceAllMetadata = "all" === dlg.querySelector("#selectMetadataRefreshMode").value, - mode = "scan" === dlg.querySelector("#selectMetadataRefreshMode").value ? "Default" : "FullRefresh", - replaceAllImages = "FullRefresh" === mode && dlg.querySelector(".chkReplaceImages").checked; - return options.itemIds.forEach(function(itemId) { + + var instance = this; + var dlg = parentWithClass(e.target, 'dialog'); + var options = instance.options; + + var apiClient = connectionManager.getApiClient(options.serverId); + + var replaceAllMetadata = dlg.querySelector('#selectMetadataRefreshMode').value === 'all'; + + var mode = dlg.querySelector('#selectMetadataRefreshMode').value === 'scan' ? 'Default' : 'FullRefresh'; + var replaceAllImages = mode === 'FullRefresh' && dlg.querySelector('.chkReplaceImages').checked; + + options.itemIds.forEach(function (itemId) { apiClient.refreshItem(itemId, { - Recursive: !0, + + Recursive: true, ImageRefreshMode: mode, MetadataRefreshMode: mode, ReplaceAllImages: replaceAllImages, ReplaceAllMetadata: replaceAllMetadata - }) - }), dialogHelper.close(dlg), require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#RefreshQueued")) - }), loading.hide(), e.preventDefault(), !1 + }); + }); + + dialogHelper.close(dlg); + + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#RefreshQueued')); + }); + + loading.hide(); + + e.preventDefault(); + return false; } function RefreshDialog(options) { - this.options = options + this.options = options; } - return RefreshDialog.prototype.show = function() { + + RefreshDialog.prototype.show = function () { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'small'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - var html = "", - title = globalize.translate("sharedcomponents#RefreshMetadata"); - return html += '
', html += '', html += '

', html += title, html += "

", html += "
", html += getEditorHtml(), dlg.innerHTML = html, dlg.querySelector("form").addEventListener("submit", onSubmit.bind(this)), dlg.querySelector("#selectMetadataRefreshMode").addEventListener("change", function() { - "scan" === this.value ? dlg.querySelector(".fldReplaceExistingImages").classList.add("hide") : dlg.querySelector(".fldReplaceExistingImages").classList.remove("hide") - }), this.options.mode && (dlg.querySelector("#selectMetadataRefreshMode").value = this.options.mode), dlg.querySelector("#selectMetadataRefreshMode").dispatchEvent(new CustomEvent("change")), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), new Promise(function(resolve, reject) { - layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), dlg.addEventListener("close", resolve), dialogHelper.open(dlg) - }) - }, RefreshDialog + + dlg.classList.add('formDialog'); + + var html = ''; + var title = globalize.translate('sharedcomponents#RefreshMetadata'); + + html += '
'; + html += ''; + html += '

'; + html += title; + html += '

'; + + html += '
'; + + html += getEditorHtml(); + + dlg.innerHTML = html; + + dlg.querySelector('form').addEventListener('submit', onSubmit.bind(this)); + + dlg.querySelector('#selectMetadataRefreshMode').addEventListener('change', function () { + + if (this.value === 'scan') { + dlg.querySelector('.fldReplaceExistingImages').classList.add('hide'); + } else { + dlg.querySelector('.fldReplaceExistingImages').classList.remove('hide'); + } + }); + + if (this.options.mode) { + dlg.querySelector('#selectMetadataRefreshMode').value = this.options.mode; + } + + dlg.querySelector('#selectMetadataRefreshMode').dispatchEvent(new CustomEvent('change')); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + + return new Promise(function (resolve, reject) { + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + dlg.addEventListener('close', resolve); + dialogHelper.open(dlg); + }); + }; + + return RefreshDialog; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/registrationservices/registrationservices.js b/src/bower_components/emby-webcomponents/registrationservices/registrationservices.js index f9e96460d4..192231bc6c 100644 --- a/src/bower_components/emby-webcomponents/registrationservices/registrationservices.js +++ b/src/bower_components/emby-webcomponents/registrationservices/registrationservices.js @@ -1,301 +1,760 @@ -define(["appSettings", "loading", "apphost", "iapManager", "events", "shell", "globalize", "dialogHelper", "connectionManager", "layoutManager", "emby-button", "emby-linkbutton"], function(appSettings, loading, appHost, iapManager, events, shell, globalize, dialogHelper, connectionManager, layoutManager) { - "use strict"; +define(['appSettings', 'loading', 'apphost', 'iapManager', 'events', 'shell', 'globalize', 'dialogHelper', 'connectionManager', 'layoutManager', 'emby-button', 'emby-linkbutton'], function (appSettings, loading, appHost, iapManager, events, shell, globalize, dialogHelper, connectionManager, layoutManager) { + 'use strict'; + + var currentDisplayingProductInfos = []; + var currentDisplayingResolve = null; + var currentValidatingFeature = null; + var isCurrentDialogRejected = null; function alertText(options) { - return new Promise(function(resolve, reject) { - require(["alert"], function(alert) { - alert(options).then(resolve, reject) - }) - }) + return new Promise(function (resolve, reject) { + + require(['alert'], function (alert) { + alert(options).then(resolve, reject); + }); + }); } function showInAppPurchaseInfo(subscriptionOptions, unlockableProductInfo, dialogOptions) { - return new Promise(function(resolve, reject) { - require(["listViewStyle", "formDialogStyle"], function() { - showInAppPurchaseElement(subscriptionOptions, unlockableProductInfo, dialogOptions, resolve, reject), currentDisplayingResolve = resolve - }) - }) + + return new Promise(function (resolve, reject) { + + require(['listViewStyle', 'formDialogStyle'], function () { + showInAppPurchaseElement(subscriptionOptions, unlockableProductInfo, dialogOptions, resolve, reject); + + currentDisplayingResolve = resolve; + }); + }); } function showPeriodicMessage(feature, settingsKey) { - return new Promise(function(resolve, reject) { - require(["listViewStyle", "emby-button", "formDialogStyle"], function() { + + return new Promise(function (resolve, reject) { + + require(['listViewStyle', 'emby-button', 'formDialogStyle'], function () { + var dlg = dialogHelper.createDialog({ - size: layoutManager.tv ? "fullscreen" : "fullscreen-border", - removeOnClose: !0, - scrollY: !1 + size: layoutManager.tv ? 'fullscreen' : 'fullscreen-border', + removeOnClose: true, + scrollY: false }); - dlg.classList.add("formDialog"); - var html = ""; + + dlg.classList.add('formDialog'); + + var html = ''; + html += '
'; + html += ''; + html += '

Emby Premiere'; + html += '

'; + html += '
'; + + + html += '
'; + html += '
'; + + html += '

' + globalize.translate('sharedcomponents#HeaderDiscoverEmbyPremiere') + '

'; + + html += '

' + globalize.translate('sharedcomponents#MessageDidYouKnowCinemaMode') + '

'; + html += '

' + globalize.translate('sharedcomponents#MessageDidYouKnowCinemaMode2') + '

'; + + html += '

' + globalize.translate('sharedcomponents#HeaderBenefitsEmbyPremiere') + '

'; + + html += '
'; + html += getSubscriptionBenefits().map(getSubscriptionBenefitHtml).join(''); + html += '
'; + + html += '
'; + + html += '
'; + + html += ''; + var seconds = 11; - html += '
' + globalize.translate("sharedcomponents#ContinueInSecondsValue", seconds) + "
", html += '", html += "
", html += "
", html += "
", dlg.innerHTML = html; - var i, length, isRejected = !0, - timeTextInterval = setInterval(function() { - seconds -= 1, seconds <= 0 ? (dlg.querySelector(".continueTimeText").classList.add("hide"), dlg.querySelector(".btnContinue").classList.remove("hide")) : dlg.querySelector(".continueTimeText").innerHTML = globalize.translate("sharedcomponents#ContinueInSecondsValue", seconds) - }, 1e3), - btnPurchases = dlg.querySelectorAll(".buttonPremiereInfo"); - for (i = 0, length = btnPurchases.length; i < length; i++) btnPurchases[i].addEventListener("click", showExternalPremiereInfo); - layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), dlg.addEventListener("close", function(e) { - clearInterval(timeTextInterval), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), isRejected ? reject() : (appSettings.set(settingsKey, (new Date).getTime()), resolve()) - }), dlg.querySelector(".btnContinue").addEventListener("click", function() { - isRejected = !1, dialogHelper.close(dlg) - }), dlg.querySelector(".btnGetPremiere").addEventListener("click", showPremiereInfo), dialogHelper.open(dlg); - var onCancelClick = function() { - dialogHelper.close(dlg) - }, - elems = dlg.querySelectorAll(".btnCancelSupporterInfo"); - for (i = 0, length = elems.length; i < length; i++) elems[i].addEventListener("click", onCancelClick) - }) - }) + + html += '
' + globalize.translate('sharedcomponents#ContinueInSecondsValue', seconds) + '
'; + + html += ''; + + html += '
'; + + html += '
'; + html += '
'; + + dlg.innerHTML = html; + + var isRejected = true; + + var timeTextInterval = setInterval(function () { + + seconds -= 1; + if (seconds <= 0) { + dlg.querySelector('.continueTimeText').classList.add('hide'); + dlg.querySelector('.btnContinue').classList.remove('hide'); + } else { + dlg.querySelector('.continueTimeText').innerHTML = globalize.translate('sharedcomponents#ContinueInSecondsValue', seconds); + } + + }, 1000); + + var i, length; + var btnPurchases = dlg.querySelectorAll('.buttonPremiereInfo'); + for (i = 0, length = btnPurchases.length; i < length; i++) { + btnPurchases[i].addEventListener('click', showExternalPremiereInfo); + } + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + + // Has to be assigned a z-index after the call to .open() + dlg.addEventListener('close', function (e) { + + clearInterval(timeTextInterval); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + if (isRejected) { + reject(); + } else { + appSettings.set(settingsKey, new Date().getTime()); + + resolve(); + } + }); + + dlg.querySelector('.btnContinue').addEventListener('click', function () { + isRejected = false; + dialogHelper.close(dlg); + }); + + dlg.querySelector('.btnGetPremiere').addEventListener('click', showPremiereInfo); + + dialogHelper.open(dlg); + + var onCancelClick = function () { + dialogHelper.close(dlg); + }; + var elems = dlg.querySelectorAll('.btnCancelSupporterInfo'); + for (i = 0, length = elems.length; i < length; i++) { + elems[i].addEventListener('click', onCancelClick); + } + }); + }); } function showPeriodicMessageIfNeeded(feature) { - if ("playback" !== feature) return Promise.resolve(); - var intervalMs = iapManager.getPeriodicMessageIntervalMs(feature); - if (intervalMs <= 0) return Promise.resolve(); - var settingsKey = "periodicmessage11-" + feature, - lastMessage = parseInt(appSettings.get(settingsKey) || "0"); - if (!lastMessage) return appSettings.set(settingsKey, (new Date).getTime()), Promise.resolve(); - if ((new Date).getTime() - lastMessage > intervalMs) { - var apiClient = connectionManager.currentApiClient(); - if ("6da60dd6edfc4508bca2c434d4400816" === apiClient.serverId()) return Promise.resolve(); - var registrationOptions = { - viewOnly: !0 - }; - return connectionManager.getRegistrationInfo(iapManager.getAdminFeatureName(feature), apiClient, registrationOptions).catch(function(errorResult) { - return "overlimit" === errorResult ? (appSettings.set(settingsKey, (new Date).getTime()), Promise.resolve()) : showPeriodicMessage(feature, settingsKey) - }) + + if (feature !== 'playback') { + return Promise.resolve(); } - return Promise.resolve() + + var intervalMs = iapManager.getPeriodicMessageIntervalMs(feature); + if (intervalMs <= 0) { + return Promise.resolve(); + } + + var settingsKey = 'periodicmessage11-' + feature; + + var lastMessage = parseInt(appSettings.get(settingsKey) || '0'); + + if (!lastMessage) { + + // Don't show on the very first playback attempt + appSettings.set(settingsKey, new Date().getTime()); + return Promise.resolve(); + } + + if ((new Date().getTime() - lastMessage) > intervalMs) { + + var apiClient = connectionManager.currentApiClient(); + if (apiClient.serverId() === '6da60dd6edfc4508bca2c434d4400816') { + return Promise.resolve(); + } + + var registrationOptions = { + viewOnly: true + }; + + // Get supporter status + return connectionManager.getRegistrationInfo(iapManager.getAdminFeatureName(feature), apiClient, registrationOptions).catch(function (errorResult) { + + if (errorResult === 'overlimit') { + appSettings.set(settingsKey, new Date().getTime()); + return Promise.resolve(); + } + + return showPeriodicMessage(feature, settingsKey); + }); + } + + return Promise.resolve(); } function validateFeature(feature, options) { - return options = options || {}, console.log("validateFeature: " + feature), iapManager.isUnlockedByDefault(feature, options).then(function() { - return showPeriodicMessageIfNeeded(feature) - }, function() { - var unlockableFeatureCacheKey = "featurepurchased-" + feature; - if ("1" === appSettings.get(unlockableFeatureCacheKey)) return showPeriodicMessageIfNeeded(feature); + + options = options || {}; + + console.log('validateFeature: ' + feature); + + return iapManager.isUnlockedByDefault(feature, options).then(function () { + + return showPeriodicMessageIfNeeded(feature); + + }, function () { + + var unlockableFeatureCacheKey = 'featurepurchased-' + feature; + if (appSettings.get(unlockableFeatureCacheKey) === '1') { + return showPeriodicMessageIfNeeded(feature); + } + var unlockableProduct = iapManager.getProductInfo(feature); if (unlockableProduct) { - var unlockableCacheKey = "productpurchased-" + unlockableProduct.id; - if (unlockableProduct.owned) return appSettings.set(unlockableFeatureCacheKey, "1"), appSettings.set(unlockableCacheKey, "1"), showPeriodicMessageIfNeeded(feature); - if ("1" === appSettings.get(unlockableCacheKey)) return showPeriodicMessageIfNeeded(feature) + + var unlockableCacheKey = 'productpurchased-' + unlockableProduct.id; + if (unlockableProduct.owned) { + + // Cache this to eliminate the store as a possible point of failure in the future + appSettings.set(unlockableFeatureCacheKey, '1'); + appSettings.set(unlockableCacheKey, '1'); + return showPeriodicMessageIfNeeded(feature); + } + + if (appSettings.get(unlockableCacheKey) === '1') { + return showPeriodicMessageIfNeeded(feature); + } } + var unlockableProductInfo = unlockableProduct ? { - enableAppUnlock: !0, + enableAppUnlock: true, id: unlockableProduct.id, price: unlockableProduct.price, feature: feature + } : null; - return iapManager.getSubscriptionOptions().then(function(subscriptionOptions) { - if (subscriptionOptions.filter(function(p) { - return p.owned - }).length > 0) return Promise.resolve(); + + return iapManager.getSubscriptionOptions().then(function (subscriptionOptions) { + + if (subscriptionOptions.filter(function (p) { + return p.owned; + }).length > 0) { + return Promise.resolve(); + } + var registrationOptions = { viewOnly: options.viewOnly }; - return connectionManager.getRegistrationInfo(iapManager.getAdminFeatureName(feature), connectionManager.currentApiClient(), registrationOptions).catch(function(errorResult) { - if (!1 === options.showDialog) return Promise.reject(); + + // Get supporter status + return connectionManager.getRegistrationInfo(iapManager.getAdminFeatureName(feature), connectionManager.currentApiClient(), registrationOptions).catch(function (errorResult) { + + if (options.showDialog === false) { + return Promise.reject(); + } + var alertPromise; - return "overlimit" === errorResult && (alertPromise = showOverLimitAlert()), alertPromise || (alertPromise = Promise.resolve()), alertPromise.then(function() { + + if (errorResult === 'overlimit') { + alertPromise = showOverLimitAlert(); + } + + if (!alertPromise) { + alertPromise = Promise.resolve(); + } + + return alertPromise.then(function () { + var dialogOptions = { - title: globalize.translate("sharedcomponents#HeaderUnlockFeature"), + title: globalize.translate('sharedcomponents#HeaderUnlockFeature'), feature: feature }; - return currentValidatingFeature = feature, showInAppPurchaseInfo(subscriptionOptions, unlockableProductInfo, dialogOptions) - }) - }) - }) - }) + + currentValidatingFeature = feature; + + return showInAppPurchaseInfo(subscriptionOptions, unlockableProductInfo, dialogOptions); + }); + }); + }); + }); } function showOverLimitAlert() { - return alertText("Your Jellyfin Premiere device limit has been exceeded. Please check with the owner of your Jellyfin Server and have them contact Jellyfin support at apps@emby.media if necessary.").catch(function() { - return Promise.resolve() - }) + + return alertText('Your Emby Premiere device limit has been exceeded. Please check with the owner of your Emby Server and have them contact Emby support at apps@emby.media if necessary.').catch(function () { + return Promise.resolve(); + }); } function cancelInAppPurchase() { - var elem = document.querySelector(".inAppPurchaseOverlay"); - elem && dialogHelper.close(elem) + + var elem = document.querySelector('.inAppPurchaseOverlay'); + if (elem) { + dialogHelper.close(elem); + } } function clearCurrentDisplayingInfo() { - currentDisplayingProductInfos = [], currentDisplayingResolve = null, currentValidatingFeature = null, isCurrentDialogRejected = null + currentDisplayingProductInfos = []; + currentDisplayingResolve = null; + currentValidatingFeature = null; + isCurrentDialogRejected = null; } function showExternalPremiereInfo() { - shell.openUrl(iapManager.getPremiumInfoUrl()) + shell.openUrl(iapManager.getPremiumInfoUrl()); } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function getPurchaseTermHtml(term) { - return "
  • " + term + "
  • " + + return '
  • ' + term + '
  • '; } function getTermsOfPurchaseHtml() { - var html = "", - termsOfPurchase = iapManager.getTermsOfPurchase ? iapManager.getTermsOfPurchase() : []; - return termsOfPurchase.length ? (html += "

    " + globalize.translate("sharedcomponents#HeaderTermsOfPurchase") + "

    ", termsOfPurchase.push('' + globalize.translate("sharedcomponents#PrivacyPolicy") + ""), termsOfPurchase.push('' + globalize.translate("sharedcomponents#TermsOfUse") + ""), html += "
      ", html += termsOfPurchase.map(getPurchaseTermHtml).join(""), html += "
    ") : html + + var html = ''; + + var termsOfPurchase = iapManager.getTermsOfPurchase ? iapManager.getTermsOfPurchase() : []; + + if (!termsOfPurchase.length) { + + return html; + } + + html += '

    ' + globalize.translate('sharedcomponents#HeaderTermsOfPurchase') + '

    '; + + termsOfPurchase.push('' + globalize.translate('sharedcomponents#PrivacyPolicy') + ''); + termsOfPurchase.push('' + globalize.translate('sharedcomponents#TermsOfUse') + ''); + + html += '
      '; + html += termsOfPurchase.map(getPurchaseTermHtml).join(''); + html += '
    '; + + return html; } function showInAppPurchaseElement(subscriptionOptions, unlockableProductInfo, dialogOptions, resolve, reject) { - function onCloseButtonClick() { - dialogHelper.close(dlg) - } - cancelInAppPurchase(), currentDisplayingProductInfos = subscriptionOptions.slice(0), unlockableProductInfo && currentDisplayingProductInfos.push(unlockableProductInfo); - var dlg = dialogHelper.createDialog({ - size: layoutManager.tv ? "fullscreen" : "fullscreen-border", - removeOnClose: !0, - scrollY: !1 - }); - dlg.classList.add("formDialog"); - var html = ""; - html += '
    ', html += '', html += '

    ', html += dialogOptions.title || "", html += "

    ", html += "
    ", html += '
    ', html += '
    ', html += '
    ', html += '

    ', html += unlockableProductInfo ? globalize.translate("sharedcomponents#MessageUnlockAppWithPurchaseOrSupporter") : globalize.translate("sharedcomponents#MessageUnlockAppWithSupporter"), html += "

    ", html += '

    ', html += globalize.translate("sharedcomponents#MessageToValidateSupporter"), html += "

    "; - var i, length; - for (i = 0, length = subscriptionOptions.length; i < length; i++) !0, html += "

    ", html += '", html += "

    "; + + cancelInAppPurchase(); + + // clone + currentDisplayingProductInfos = subscriptionOptions.slice(0); + if (unlockableProductInfo) { - !0; - var unlockText = globalize.translate("sharedcomponents#ButtonUnlockWithPurchase"); - unlockableProductInfo.price && (unlockText = globalize.translate("sharedcomponents#ButtonUnlockPrice", unlockableProductInfo.price)), html += "

    ", html += '", html += "

    " + currentDisplayingProductInfos.push(unlockableProductInfo); } - html += "

    ", html += '", html += "

    ", subscriptionOptions.length && (html += '

    ' + globalize.translate("sharedcomponents#HeaderBenefitsJellyfinPremiere") + "

    ", html += '
    ', html += getSubscriptionBenefits().map(getSubscriptionBenefitHtml).join(""), html += "
    "), "playback" === dialogOptions.feature && (html += "

    ", html += '", html += "

    "), html += getTermsOfPurchaseHtml(), html += "
    ", html += "
    ", html += "
    ", dlg.innerHTML = html, document.body.appendChild(dlg); - var btnPurchases = dlg.querySelectorAll(".btnPurchase"); - for (i = 0, length = btnPurchases.length; i < length; i++) btnPurchases[i].addEventListener("click", onPurchaseButtonClick); - for (btnPurchases = dlg.querySelectorAll(".buttonPremiereInfo"), i = 0, length = btnPurchases.length; i < length; i++) btnPurchases[i].addEventListener("click", showExternalPremiereInfo); - isCurrentDialogRejected = !0; - var resolveWithTimeLimit = !1, - btnPlayMinute = dlg.querySelector(".btnPlayMinute"); - btnPlayMinute && btnPlayMinute.addEventListener("click", function() { - resolveWithTimeLimit = !0, isCurrentDialogRejected = !1, dialogHelper.close(dlg) - }), dlg.querySelector(".btnRestorePurchase").addEventListener("click", function() { - restorePurchase(unlockableProductInfo) - }), loading.hide(); - var btnCloseDialogs = dlg.querySelectorAll(".btnCloseDialog"); - for (i = 0, length = btnCloseDialogs.length; i < length; i++) btnCloseDialogs[i].addEventListener("click", onCloseButtonClick); - dlg.classList.add("inAppPurchaseOverlay"), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), dialogHelper.open(dlg).then(function() { - layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1); + + var dlg = dialogHelper.createDialog({ + size: layoutManager.tv ? 'fullscreen' : 'fullscreen-border', + removeOnClose: true, + scrollY: false + }); + + dlg.classList.add('formDialog'); + + var html = ''; + html += '
    '; + html += ''; + html += '

    '; + html += dialogOptions.title || ''; + html += '

    '; + html += '
    '; + + html += '
    '; + html += '
    '; + html += '
    '; + + html += '

    '; + + if (unlockableProductInfo) { + html += globalize.translate('sharedcomponents#MessageUnlockAppWithPurchaseOrSupporter'); + } + else { + html += globalize.translate('sharedcomponents#MessageUnlockAppWithSupporter'); + } + html += '

    '; + + html += '

    '; + html += globalize.translate('sharedcomponents#MessageToValidateSupporter'); + html += '

    '; + + var hasProduct = false; + var i, length; + + for (i = 0, length = subscriptionOptions.length; i < length; i++) { + + hasProduct = true; + html += '

    '; + html += ''; + html += '

    '; + } + + if (unlockableProductInfo) { + + hasProduct = true; + var unlockText = globalize.translate('sharedcomponents#ButtonUnlockWithPurchase'); + if (unlockableProductInfo.price) { + unlockText = globalize.translate('sharedcomponents#ButtonUnlockPrice', unlockableProductInfo.price); + } + html += '

    '; + html += ''; + html += '

    '; + } + + html += '

    '; + html += ''; + html += '

    '; + + if (subscriptionOptions.length) { + html += '

    ' + globalize.translate('sharedcomponents#HeaderBenefitsEmbyPremiere') + '

    '; + + html += '
    '; + html += getSubscriptionBenefits().map(getSubscriptionBenefitHtml).join(''); + html += '
    '; + } + + if (dialogOptions.feature === 'playback') { + html += '

    '; + html += ''; + html += '

    '; + } + + html += getTermsOfPurchaseHtml(); + + html += '
    '; + html += '
    '; + html += '
    '; + + dlg.innerHTML = html; + document.body.appendChild(dlg); + + var btnPurchases = dlg.querySelectorAll('.btnPurchase'); + for (i = 0, length = btnPurchases.length; i < length; i++) { + btnPurchases[i].addEventListener('click', onPurchaseButtonClick); + } + + btnPurchases = dlg.querySelectorAll('.buttonPremiereInfo'); + for (i = 0, length = btnPurchases.length; i < length; i++) { + btnPurchases[i].addEventListener('click', showExternalPremiereInfo); + } + + isCurrentDialogRejected = true; + var resolveWithTimeLimit = false; + + var btnPlayMinute = dlg.querySelector('.btnPlayMinute'); + if (btnPlayMinute) { + btnPlayMinute.addEventListener('click', function () { + + resolveWithTimeLimit = true; + isCurrentDialogRejected = false; + dialogHelper.close(dlg); + }); + } + + dlg.querySelector('.btnRestorePurchase').addEventListener('click', function () { + restorePurchase(unlockableProductInfo); + }); + + loading.hide(); + + function onCloseButtonClick() { + + dialogHelper.close(dlg); + } + + var btnCloseDialogs = dlg.querySelectorAll('.btnCloseDialog'); + for (i = 0, length = btnCloseDialogs.length; i < length; i++) { + btnCloseDialogs[i].addEventListener('click', onCloseButtonClick); + } + + dlg.classList.add('inAppPurchaseOverlay'); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + + dialogHelper.open(dlg).then(function () { + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + var rejected = isCurrentDialogRejected; - clearCurrentDisplayingInfo(), rejected ? reject() : resolveWithTimeLimit && resolve({ - enableTimeLimit: !0 - }) - }) + clearCurrentDisplayingInfo(); + if (rejected) { + reject(); + } else if (resolveWithTimeLimit) { + resolve({ + enableTimeLimit: true + }); + } + }); } function getSubscriptionBenefits() { + var list = []; - return list.push({ - name: globalize.translate("sharedcomponents#HeaderFreeApps"), - icon: "", - text: globalize.translate("sharedcomponents#FreeAppsFeatureDescription") - }), appHost.supports("sync") && list.push({ - name: globalize.translate("sharedcomponents#HeaderOfflineDownloads"), - icon: "", - text: globalize.translate("sharedcomponents#HeaderOfflineDownloadsDescription") - }), list.push({ - name: globalize.translate("sharedcomponents#LiveTV"), - icon: "", - text: globalize.translate("sharedcomponents#LiveTvFeatureDescription") - }), list.push({ - name: "Jellyfin DVR", - icon: "", - text: globalize.translate("sharedcomponents#DvrFeatureDescription") - }), list.push({ - name: globalize.translate("sharedcomponents#HeaderCinemaMode"), - icon: "", - text: globalize.translate("sharedcomponents#CinemaModeFeatureDescription") - }), list.push({ - name: globalize.translate("sharedcomponents#HeaderCloudSync"), - icon: "", - text: globalize.translate("sharedcomponents#CloudSyncFeatureDescription") - }), list + + list.push({ + name: globalize.translate('sharedcomponents#HeaderFreeApps'), + icon: '', + text: globalize.translate('sharedcomponents#FreeAppsFeatureDescription') + }); + + if (appHost.supports('sync')) { + list.push({ + name: globalize.translate('sharedcomponents#HeaderOfflineDownloads'), + icon: '', + text: globalize.translate('sharedcomponents#HeaderOfflineDownloadsDescription') + }); + } + + list.push({ + name: globalize.translate('sharedcomponents#LiveTV'), + icon: '', + text: globalize.translate('sharedcomponents#LiveTvFeatureDescription') + }); + + list.push({ + name: 'Emby DVR', + icon: '', + text: globalize.translate('sharedcomponents#DvrFeatureDescription') + }); + + list.push({ + name: globalize.translate('sharedcomponents#HeaderCinemaMode'), + icon: '', + text: globalize.translate('sharedcomponents#CinemaModeFeatureDescription') + }); + + list.push({ + name: globalize.translate('sharedcomponents#HeaderCloudSync'), + icon: '', + text: globalize.translate('sharedcomponents#CloudSyncFeatureDescription') + }); + + return list; } function getSubscriptionBenefitHtml(item) { - var enableLink = appHost.supports("externalpremium"), - html = "", - cssClass = "listItem"; - return layoutManager.tv && (cssClass += " listItem-focusscale"), enableLink ? (cssClass += " listItem-button", html += '" : "
    " + + var enableLink = appHost.supports('externalpremium'); + + var html = ''; + + var cssClass = "listItem"; + + if (layoutManager.tv) { + cssClass += ' listItem-focusscale'; + } + + if (enableLink) { + cssClass += ' listItem-button'; + + html += ''; + } else { + html += '
    '; + } + + return html; } function onPurchaseButtonClick() { - var featureId = this.getAttribute("data-featureid"); - "true" === this.getAttribute("data-email") ? getUserEmail().then(function(email) { - iapManager.beginPurchase(featureId, email) - }) : iapManager.beginPurchase(featureId) + + var featureId = this.getAttribute('data-featureid'); + + if (this.getAttribute('data-email') === 'true') { + getUserEmail().then(function (email) { + iapManager.beginPurchase(featureId, email); + }); + } else { + iapManager.beginPurchase(featureId); + } } function restorePurchase(unlockableProductInfo) { + var dlg = dialogHelper.createDialog({ - size: layoutManager.tv ? "fullscreen" : "fullscreen-border", - removeOnClose: !0, - scrollY: !1 + size: layoutManager.tv ? 'fullscreen' : 'fullscreen-border', + removeOnClose: true, + scrollY: false }); - dlg.classList.add("formDialog"); - var html = ""; - html += '
    ', html += '', html += '

    ', html += iapManager.getRestoreButtonText(), html += "

    ", html += "
    ", html += '
    ', html += '
    ', html += '

    ', html += globalize.translate("sharedcomponents#HowDidYouPay"), html += "

    ", html += "

    ", html += '", html += "

    ", unlockableProductInfo && (html += "

    ", html += '", html += "

    "), html += "
    ", html += "
    ", dlg.innerHTML = html, document.body.appendChild(dlg), loading.hide(), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), dlg.querySelector(".btnCloseDialog").addEventListener("click", function() { - dialogHelper.close(dlg) - }), dlg.querySelector(".btnRestoreSub").addEventListener("click", function() { - dialogHelper.close(dlg), alertText({ - text: globalize.translate("sharedcomponents#MessageToValidateSupporter"), - title: "Jellyfin Premiere" - }) + + dlg.classList.add('formDialog'); + + var html = ''; + html += '
    '; + html += ''; + html += '

    '; + html += iapManager.getRestoreButtonText(); + html += '

    '; + html += '
    '; + + html += '
    '; + html += '
    '; + + html += '

    '; + html += globalize.translate('sharedcomponents#HowDidYouPay'); + html += '

    '; + + html += '

    '; + html += ''; + html += '

    '; + + if (unlockableProductInfo) { + html += '

    '; + html += ''; + html += '

    '; + } + + html += '
    '; + html += '
    '; + + dlg.innerHTML = html; + document.body.appendChild(dlg); + + loading.hide(); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + + dlg.querySelector('.btnCloseDialog').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + + dlg.querySelector('.btnRestoreSub').addEventListener('click', function () { + + dialogHelper.close(dlg); + alertText({ + text: globalize.translate('sharedcomponents#MessageToValidateSupporter'), + title: 'Emby Premiere' + }); + + }); + + var btnRestoreUnlock = dlg.querySelector('.btnRestoreUnlock'); + if (btnRestoreUnlock) { + btnRestoreUnlock.addEventListener('click', function () { + + dialogHelper.close(dlg); + iapManager.restorePurchase(); + }); + } + + dialogHelper.open(dlg).then(function () { + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } }); - var btnRestoreUnlock = dlg.querySelector(".btnRestoreUnlock"); - btnRestoreUnlock && btnRestoreUnlock.addEventListener("click", function() { - dialogHelper.close(dlg), iapManager.restorePurchase() - }), dialogHelper.open(dlg).then(function() { - layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1) - }) } function getUserEmail() { + if (connectionManager.isLoggedIntoConnect()) { + var connectUser = connectionManager.connectUser(); - if (connectUser && connectUser.Email) return Promise.resolve(connectUser.Email) + + if (connectUser && connectUser.Email) { + return Promise.resolve(connectUser.Email); + } } - return new Promise(function(resolve, reject) { - require(["prompt"], function(prompt) { + + return new Promise(function (resolve, reject) { + + require(['prompt'], function (prompt) { + prompt({ - label: globalize.translate("sharedcomponents#LabelEmailAddress") - }).then(resolve, reject) - }) - }) + + label: globalize.translate('sharedcomponents#LabelEmailAddress') + + }).then(resolve, reject); + }); + }); } function onProductUpdated(e, product) { + if (product.owned) { + var resolve = currentDisplayingResolve; - if (resolve && currentDisplayingProductInfos.filter(function(p) { - return product.id === p.id - }).length) return isCurrentDialogRejected = !1, cancelInAppPurchase(), void resolve() + + if (resolve && currentDisplayingProductInfos.filter(function (p) { + + return product.id === p.id; + + }).length) { + + isCurrentDialogRejected = false; + cancelInAppPurchase(); + resolve(); + return; + } } + var feature = currentValidatingFeature; - feature && iapManager.isUnlockedByDefault(feature).then(function() { - isCurrentDialogRejected = !1, cancelInAppPurchase(), resolve() - }) + if (feature) { + iapManager.isUnlockedByDefault(feature).then(function () { + isCurrentDialogRejected = false; + cancelInAppPurchase(); + resolve(); + }); + } } function showPremiereInfo() { - return appHost.supports("externalpremium") ? (showExternalPremiereInfo(), Promise.resolve()) : iapManager.getSubscriptionOptions().then(function(subscriptionOptions) { - return showInAppPurchaseInfo(subscriptionOptions, null, { - title: "Jellyfin Premiere", - feature: "sync" - }) - }) + + if (appHost.supports('externalpremium')) { + showExternalPremiereInfo(); + return Promise.resolve(); + } + + return iapManager.getSubscriptionOptions().then(function (subscriptionOptions) { + + var dialogOptions = { + title: 'Emby Premiere', + feature: 'sync' + }; + + return showInAppPurchaseInfo(subscriptionOptions, null, dialogOptions); + }); } - var currentDisplayingProductInfos = [], - currentDisplayingResolve = null, - currentValidatingFeature = null, - isCurrentDialogRejected = null; - return events.on(iapManager, "productupdated", onProductUpdated), { + + events.on(iapManager, 'productupdated', onProductUpdated); + + return { + validateFeature: validateFeature, showPremiereInfo: showPremiereInfo - } -}); + }; +}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/require/requirecss.js b/src/bower_components/emby-webcomponents/require/requirecss.js index 5e158496cf..f65ed1fd04 100644 --- a/src/bower_components/emby-webcomponents/require/requirecss.js +++ b/src/bower_components/emby-webcomponents/require/requirecss.js @@ -1,35 +1,75 @@ -define(function() { - "use strict"; +define(function () { + 'use strict'; + + var requireCss = {}; + + requireCss.normalize = function (name, normalize) { + if (name.substr(name.length - 4, 4) === '.css') { + name = name.substr(0, name.length - 4); + } + + return normalize(name); + }; + + var importedCss = []; function isLoaded(url) { - return -1 !== importedCss.indexOf(url) + return importedCss.indexOf(url) !== -1; } function removeFromLoadHistory(url) { - url = url.toLowerCase(), importedCss = importedCss.filter(function(c) { - return -1 === url.indexOf(c.toLowerCase()) - }) + + url = url.toLowerCase(); + + importedCss = importedCss.filter(function (c) { + return url.indexOf(c.toLowerCase()) === -1; + }); } - var requireCss = {}; - requireCss.normalize = function(name, normalize) { - return ".css" === name.substr(name.length - 4, 4) && (name = name.substr(0, name.length - 4)), normalize(name) - }; - var importedCss = []; - return requireCss.load = function(cssId, req, load, config) { - var srch = "/emby-webcomponents/require/requirecss", - index = cssId.indexOf(srch); - 1 !== index && (cssId = "css" + cssId.substring(index + srch.length)); - var url = cssId + ".css"; - if (-1 === url.indexOf("://") && (url = config.baseUrl + url), isLoaded(url)) load(); - else { + + requireCss.load = function (cssId, req, load, config) { + + // Somehow if the url starts with /css, require will get all screwed up since this extension is also called css + var srch = '/emby-webcomponents/require/requirecss'; + var index = cssId.indexOf(srch); + + if (index !== -1) { + cssId = 'css' + cssId.substring(index + srch.length); + } + + var url = cssId + '.css'; + + if (url.indexOf('://') === -1) { + url = config.baseUrl + url; + } + + if (!isLoaded(url)) { importedCss.push(url); - var link = document.createElement("link"); - link.setAttribute("rel", "stylesheet"), link.setAttribute("type", "text/css"), link.onload = load; + + var link = document.createElement('link'); + + link.setAttribute('rel', 'stylesheet'); + link.setAttribute('type', 'text/css'); + link.onload = load; + var linkUrl = url; - config.urlArgs && (linkUrl += config.urlArgs(cssId, url)), link.setAttribute("href", linkUrl), document.head.appendChild(link) + + if (config.urlArgs) { + linkUrl += config.urlArgs(cssId, url); + } + link.setAttribute('href', linkUrl); + document.head.appendChild(link); + } else { + load(); } - }, window.requireCss = { - removeStylesheet: function(stylesheet) { - stylesheet.parentNode.removeChild(stylesheet), removeFromLoadHistory(stylesheet.href) + }; + + window.requireCss = { + removeStylesheet: function (stylesheet) { + + stylesheet.parentNode.removeChild(stylesheet); + removeFromLoadHistory(stylesheet.href); } - }, requireCss -}); \ No newline at end of file + }; + + return requireCss; +}); diff --git a/src/bower_components/emby-webcomponents/require/requiretext.js b/src/bower_components/emby-webcomponents/require/requiretext.js index c31826f81c..b035b4744d 100644 --- a/src/bower_components/emby-webcomponents/require/requiretext.js +++ b/src/bower_components/emby-webcomponents/require/requiretext.js @@ -1,16 +1,43 @@ -define(function() { - "use strict"; - var addRedirectPrevention = null != self.dashboardVersion && self.Dashboard && !self.AppInfo.isNativeApp; +define(function () { + 'use strict'; + + // hack to work around the server's auto-redirection feature + var addRedirectPrevention = self.dashboardVersion != null && self.Dashboard && !self.Dashboard.isConnectMode(); + return { - load: function(url, req, load, config) { - -1 === url.indexOf("://") && (url = config.baseUrl + url), config.urlArgs && (url += config.urlArgs(url, url)), addRedirectPrevention && (-1 === url.indexOf("?") ? url += "?" : url += "&", url += "r=0"); - var xhr = new XMLHttpRequest; - xhr.open("GET", url, !0), xhr.onload = function(e) { - load(this.response) - }, xhr.send() + + load: function (url, req, load, config) { + + if (url.indexOf('://') === -1) { + url = config.baseUrl + url; + } + + if (config.urlArgs) { + url += config.urlArgs(url, url); + } + + if (addRedirectPrevention) { + if (url.indexOf('?') === -1) { + url += '?'; + } else { + url += '&'; + } + + url += 'r=0'; + } + + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + + xhr.onload = function (e) { + load(this.response); + }; + + xhr.send(); }, - normalize: function(name, normalize) { - return normalize(name) + + normalize: function (name, normalize) { + return normalize(name); } - } -}); \ No newline at end of file + }; +}); diff --git a/src/bower_components/emby-webcomponents/resize-observer-polyfill/ResizeObserver.js b/src/bower_components/emby-webcomponents/resize-observer-polyfill/ResizeObserver.js index 4b7687b2f4..d9f152c827 100644 --- a/src/bower_components/emby-webcomponents/resize-observer-polyfill/ResizeObserver.js +++ b/src/bower_components/emby-webcomponents/resize-observer-polyfill/ResizeObserver.js @@ -1,244 +1,939 @@ -! function(global, factory) { - "object" == typeof exports && "undefined" != typeof module ? module.exports = factory() : "function" == typeof define && define.amd ? define(factory) : global.ResizeObserver = factory() -}(this, function() { - "use strict"; +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.ResizeObserver = factory()); +}(this, (function () { 'use strict'; - function getHTMLElementContentRect(target) { - var rect = target.getBoundingClientRect(); - return createRectInit(rect.left, rect.top, rect.width, rect.height) +/** + * A collection of shims that provide minimal functionality of the ES6 collections. + * + * These implementations are not meant to be used outside of the ResizeObserver + * modules as they cover only a limited range of use cases. + */ +/* eslint-disable require-jsdoc, valid-jsdoc */ +var MapShim = (function () { + if (typeof Map !== 'undefined') { + return Map; } - function getContentRect(target) { - return isBrowser ? getHTMLElementContentRect(target) : emptyRect - } + /** + * Returns index in provided array that matches the specified key. + * + * @param {Array} arr + * @param {*} key + * @returns {number} + */ + function getIndex(arr, key) { + var result = -1; - function createReadOnlyRect(ref) { - var x = ref.x, - y = ref.y, - width = ref.width, - height = ref.height, - Constr = "undefined" != typeof DOMRectReadOnly ? DOMRectReadOnly : Object, - rect = Object.create(Constr.prototype); - return defineConfigurable(rect, { - x: x, - y: y, - width: width, - height: height, - top: y, - right: x + width, - bottom: height + y, - left: x - }), rect - } + arr.some(function (entry, index) { + if (entry[0] === key) { + result = index; - function createRectInit(x, y, width, height) { - return { - x: x, - y: y, - width: width, - height: height - } - } - var MapShim = function() { - function getIndex(arr, key) { - var result = -1; - return arr.some(function(entry, index) { - return entry[0] === key && (result = index, !0) - }), result - } - return "undefined" != typeof Map ? Map : function() { - function anonymous() { - this.__entries__ = [] - } - var prototypeAccessors = { - size: { - configurable: !0 - } - }; - return prototypeAccessors.size.get = function() { - return this.__entries__.length - }, anonymous.prototype.get = function(key) { - var index = getIndex(this.__entries__, key), - entry = this.__entries__[index]; - return entry && entry[1] - }, anonymous.prototype.set = function(key, value) { - var index = getIndex(this.__entries__, key); - ~index ? this.__entries__[index][1] = value : this.__entries__.push([key, value]) - }, anonymous.prototype.delete = function(key) { - var entries = this.__entries__, - index = getIndex(entries, key); - ~index && entries.splice(index, 1) - }, anonymous.prototype.has = function(key) { - return !!~getIndex(this.__entries__, key) - }, anonymous.prototype.clear = function() { - this.__entries__.splice(0) - }, anonymous.prototype.forEach = function(callback, ctx) { - var this$1 = this; - void 0 === ctx && (ctx = null); - for (var i = 0, list = this$1.__entries__; i < list.length; i += 1) { - var entry = list[i]; - callback.call(ctx, entry[1], entry[0]) - } - }, Object.defineProperties(anonymous.prototype, prototypeAccessors), anonymous - }() - }(), - isBrowser = "undefined" != typeof window && "undefined" != typeof document && window.document === document, - global$1 = function() { - return "undefined" != typeof global && global.Math === Math ? global : "undefined" != typeof self && self.Math === Math ? self : "undefined" != typeof window && window.Math === Math ? window : Function("return this")() - }(), - requestAnimationFrame$1 = function() { - return "function" == typeof requestAnimationFrame ? requestAnimationFrame.bind(global$1) : function(callback) { - return setTimeout(function() { - return callback(Date.now()) - }, 1e3 / 60) - } - }(), - trailingTimeout = 2, - throttle = function(callback, delay) { - function resolvePending() { - leadingCall && (leadingCall = !1, callback()), trailingCall && proxy() + return true; } - function timeoutCallback() { - requestAnimationFrame$1(resolvePending) - } - - function proxy() { - var timeStamp = Date.now(); - if (leadingCall) { - if (timeStamp - lastCallTime < trailingTimeout) return; - trailingCall = !0 - } else leadingCall = !0, trailingCall = !1, setTimeout(timeoutCallback, delay); - lastCallTime = timeStamp - } - var leadingCall = !1, - trailingCall = !1, - lastCallTime = 0; - return proxy - }, - transitionKeys = ["top", "right", "bottom", "left", "width", "height", "size", "weight"], - mutationObserverSupported = "undefined" != typeof MutationObserver, - ResizeObserverController = function() { - this.connected_ = !1, this.mutationEventsAdded_ = !1, this.mutationsObserver_ = null, this.observers_ = [], this.onTransitionEnd_ = this.onTransitionEnd_.bind(this), this.refresh = throttle(this.refresh.bind(this), 20) - }; - ResizeObserverController.prototype.addObserver = function(observer) { - ~this.observers_.indexOf(observer) || this.observers_.push(observer), this.connected_ || this.connect_() - }, ResizeObserverController.prototype.removeObserver = function(observer) { - var observers = this.observers_, - index = observers.indexOf(observer); - ~index && observers.splice(index, 1), !observers.length && this.connected_ && this.disconnect_() - }, ResizeObserverController.prototype.refresh = function() { - this.updateObservers_() && this.refresh() - }, ResizeObserverController.prototype.updateObservers_ = function() { - var activeObservers = this.observers_.filter(function(observer) { - return observer.gatherActive(), observer.hasActive() + return false; }); - return activeObservers.forEach(function(observer) { - return observer.broadcastActive() - }), activeObservers.length > 0 - }, ResizeObserverController.prototype.connect_ = function() { - isBrowser && !this.connected_ && (document.addEventListener("transitionend", this.onTransitionEnd_), window.addEventListener("resize", this.refresh), window.addEventListener("orientationchange", this.refresh), mutationObserverSupported ? (this.mutationsObserver_ = new MutationObserver(this.refresh), this.mutationsObserver_.observe(document, { - attributes: !0, - childList: !0, - characterData: !0, - subtree: !0 - })) : (document.addEventListener("DOMSubtreeModified", this.refresh), this.mutationEventsAdded_ = !0), this.connected_ = !0) - }, ResizeObserverController.prototype.disconnect_ = function() { - isBrowser && this.connected_ && (document.removeEventListener("transitionend", this.onTransitionEnd_), window.removeEventListener("resize", this.refresh), window.removeEventListener("orientationchange", this.refresh), this.mutationsObserver_ && this.mutationsObserver_.disconnect(), this.mutationEventsAdded_ && document.removeEventListener("DOMSubtreeModified", this.refresh), this.mutationsObserver_ = null, this.mutationEventsAdded_ = !1, this.connected_ = !1) - }, ResizeObserverController.prototype.onTransitionEnd_ = function(ref) { - var propertyName = ref.propertyName; - void 0 === propertyName && (propertyName = ""), transitionKeys.some(function(key) { - return !!~propertyName.indexOf(key) - }) && this.refresh() - }, ResizeObserverController.getInstance = function() { - return this.instance_ || (this.instance_ = new ResizeObserverController), this.instance_ - }, ResizeObserverController.instance_ = null; - var defineConfigurable = function(target, props) { - for (var i = 0, list = Object.keys(props); i < list.length; i += 1) { - var key = list[i]; - Object.defineProperty(target, key, { - value: props[key], - enumerable: !1, - writable: !1, - configurable: !0 - }) + + return result; + } + + return (function () { + function anonymous() { + this.__entries__ = []; + } + + var prototypeAccessors = { size: { configurable: true } }; + + /** + * @returns {boolean} + */ + prototypeAccessors.size.get = function () { + return this.__entries__.length; + }; + + /** + * @param {*} key + * @returns {*} + */ + anonymous.prototype.get = function (key) { + var index = getIndex(this.__entries__, key); + var entry = this.__entries__[index]; + + return entry && entry[1]; + }; + + /** + * @param {*} key + * @param {*} value + * @returns {void} + */ + anonymous.prototype.set = function (key, value) { + var index = getIndex(this.__entries__, key); + + if (~index) { + this.__entries__[index][1] = value; + } else { + this.__entries__.push([key, value]); } - return target - }, - getWindowOf = function(target) { - return target && target.ownerDocument && target.ownerDocument.defaultView || global$1 - }, - emptyRect = createRectInit(0, 0, 0, 0), - ResizeObservation = function(target) { - this.broadcastWidth = 0, this.broadcastHeight = 0, this.contentRect_ = createRectInit(0, 0, 0, 0), this.target = target }; - ResizeObservation.prototype.isActive = function() { - var rect = getContentRect(this.target); - return this.contentRect_ = rect, rect.width !== this.broadcastWidth || rect.height !== this.broadcastHeight - }, ResizeObservation.prototype.broadcastRect = function() { - var rect = this.contentRect_; - return this.broadcastWidth = rect.width, this.broadcastHeight = rect.height, rect - }; - var ResizeObserverEntry = function(target, rectInit) { - var contentRect = createReadOnlyRect(rectInit); - defineConfigurable(this, { - target: target, - contentRect: contentRect - }) - }, - ResizeObserverSPI = function(callback, controller, callbackCtx) { - if (this.activeObservations_ = [], this.observations_ = new MapShim, "function" != typeof callback) throw new TypeError("The callback provided as parameter 1 is not a function."); - this.callback_ = callback, this.controller_ = controller, this.callbackCtx_ = callbackCtx + + /** + * @param {*} key + * @returns {void} + */ + anonymous.prototype.delete = function (key) { + var entries = this.__entries__; + var index = getIndex(entries, key); + + if (~index) { + entries.splice(index, 1); + } }; - ResizeObserverSPI.prototype.observe = function(target) { - if (!arguments.length) throw new TypeError("1 argument required, but only 0 present."); - if ("undefined" != typeof Element && Element instanceof Object) { - if (!(target instanceof getWindowOf(target).Element)) throw new TypeError('parameter 1 is not of type "Element".'); - var observations = this.observations_; - observations.has(target) || (observations.set(target, new ResizeObservation(target)), this.controller_.addObserver(this), this.controller_.refresh()) + + /** + * @param {*} key + * @returns {void} + */ + anonymous.prototype.has = function (key) { + return !!~getIndex(this.__entries__, key); + }; + + /** + * @returns {void} + */ + anonymous.prototype.clear = function () { + this.__entries__.splice(0); + }; + + /** + * @param {Function} callback + * @param {*} [ctx=null] + * @returns {void} + */ + anonymous.prototype.forEach = function (callback, ctx) { + var this$1 = this; + if ( ctx === void 0 ) ctx = null; + + for (var i = 0, list = this$1.__entries__; i < list.length; i += 1) { + var entry = list[i]; + + callback.call(ctx, entry[1], entry[0]); + } + }; + + Object.defineProperties( anonymous.prototype, prototypeAccessors ); + + return anonymous; + }()); +})(); + +/** + * Detects whether window and document objects are available in current environment. + */ +var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && window.document === document; + +// Returns global object of a current environment. +var global$1 = (function () { + if (typeof global !== 'undefined' && global.Math === Math) { + return global; + } + + if (typeof self !== 'undefined' && self.Math === Math) { + return self; + } + + if (typeof window !== 'undefined' && window.Math === Math) { + return window; + } + + // eslint-disable-next-line no-new-func + return Function('return this')(); +})(); + +/** + * A shim for the requestAnimationFrame which falls back to the setTimeout if + * first one is not supported. + * + * @returns {number} Requests' identifier. + */ +var requestAnimationFrame$1 = (function () { + if (typeof requestAnimationFrame === 'function') { + // It's required to use a bounded function because IE sometimes throws + // an "Invalid calling object" error if rAF is invoked without the global + // object on the left hand side. + return requestAnimationFrame.bind(global$1); + } + + return function (callback) { return setTimeout(function () { return callback(Date.now()); }, 1000 / 60); }; +})(); + +// Defines minimum timeout before adding a trailing call. +var trailingTimeout = 2; + +/** + * Creates a wrapper function which ensures that provided callback will be + * invoked only once during the specified delay period. + * + * @param {Function} callback - Function to be invoked after the delay period. + * @param {number} delay - Delay after which to invoke callback. + * @returns {Function} + */ +var throttle = function (callback, delay) { + var leadingCall = false, + trailingCall = false, + lastCallTime = 0; + + /** + * Invokes the original callback function and schedules new invocation if + * the "proxy" was called during current request. + * + * @returns {void} + */ + function resolvePending() { + if (leadingCall) { + leadingCall = false; + + callback(); } - }, ResizeObserverSPI.prototype.unobserve = function(target) { - if (!arguments.length) throw new TypeError("1 argument required, but only 0 present."); - if ("undefined" != typeof Element && Element instanceof Object) { - if (!(target instanceof getWindowOf(target).Element)) throw new TypeError('parameter 1 is not of type "Element".'); - var observations = this.observations_; - observations.has(target) && (observations.delete(target), observations.size || this.controller_.removeObserver(this)) + + if (trailingCall) { + proxy(); } - }, ResizeObserverSPI.prototype.disconnect = function() { - this.clearActive(), this.observations_.clear(), this.controller_.removeObserver(this) - }, ResizeObserverSPI.prototype.gatherActive = function() { + } + + /** + * Callback invoked after the specified delay. It will further postpone + * invocation of the original function delegating it to the + * requestAnimationFrame. + * + * @returns {void} + */ + function timeoutCallback() { + requestAnimationFrame$1(resolvePending); + } + + /** + * Schedules invocation of the original function. + * + * @returns {void} + */ + function proxy() { + var timeStamp = Date.now(); + + if (leadingCall) { + // Reject immediately following calls. + if (timeStamp - lastCallTime < trailingTimeout) { + return; + } + + // Schedule new call to be in invoked when the pending one is resolved. + // This is important for "transitions" which never actually start + // immediately so there is a chance that we might miss one if change + // happens amids the pending invocation. + trailingCall = true; + } else { + leadingCall = true; + trailingCall = false; + + setTimeout(timeoutCallback, delay); + } + + lastCallTime = timeStamp; + } + + return proxy; +}; + +// Minimum delay before invoking the update of observers. +var REFRESH_DELAY = 20; + +// A list of substrings of CSS properties used to find transition events that +// might affect dimensions of observed elements. +var transitionKeys = ['top', 'right', 'bottom', 'left', 'width', 'height', 'size', 'weight']; + +// Check if MutationObserver is available. +var mutationObserverSupported = typeof MutationObserver !== 'undefined'; + +/** + * Singleton controller class which handles updates of ResizeObserver instances. + */ +var ResizeObserverController = function() { + this.connected_ = false; + this.mutationEventsAdded_ = false; + this.mutationsObserver_ = null; + this.observers_ = []; + + this.onTransitionEnd_ = this.onTransitionEnd_.bind(this); + this.refresh = throttle(this.refresh.bind(this), REFRESH_DELAY); +}; + +/** + * Adds observer to observers list. + * + * @param {ResizeObserverSPI} observer - Observer to be added. + * @returns {void} + */ + + +/** + * Holds reference to the controller's instance. + * + * @private {ResizeObserverController} + */ + + +/** + * Keeps reference to the instance of MutationObserver. + * + * @private {MutationObserver} + */ + +/** + * Indicates whether DOM listeners have been added. + * + * @private {boolean} + */ +ResizeObserverController.prototype.addObserver = function (observer) { + if (!~this.observers_.indexOf(observer)) { + this.observers_.push(observer); + } + + // Add listeners if they haven't been added yet. + if (!this.connected_) { + this.connect_(); + } +}; + +/** + * Removes observer from observers list. + * + * @param {ResizeObserverSPI} observer - Observer to be removed. + * @returns {void} + */ +ResizeObserverController.prototype.removeObserver = function (observer) { + var observers = this.observers_; + var index = observers.indexOf(observer); + + // Remove observer if it's present in registry. + if (~index) { + observers.splice(index, 1); + } + + // Remove listeners if controller has no connected observers. + if (!observers.length && this.connected_) { + this.disconnect_(); + } +}; + +/** + * Invokes the update of observers. It will continue running updates insofar + * it detects changes. + * + * @returns {void} + */ +ResizeObserverController.prototype.refresh = function () { + var changesDetected = this.updateObservers_(); + + // Continue running updates if changes have been detected as there might + // be future ones caused by CSS transitions. + if (changesDetected) { + this.refresh(); + } +}; + +/** + * Updates every observer from observers list and notifies them of queued + * entries. + * + * @private + * @returns {boolean} Returns "true" if any observer has detected changes in + * dimensions of it's elements. + */ +ResizeObserverController.prototype.updateObservers_ = function () { + // Collect observers that have active observations. + var activeObservers = this.observers_.filter(function (observer) { + return observer.gatherActive(), observer.hasActive(); + }); + + // Deliver notifications in a separate cycle in order to avoid any + // collisions between observers, e.g. when multiple instances of + // ResizeObserver are tracking the same element and the callback of one + // of them changes content dimensions of the observed target. Sometimes + // this may result in notifications being blocked for the rest of observers. + activeObservers.forEach(function (observer) { return observer.broadcastActive(); }); + + return activeObservers.length > 0; +}; + +/** + * Initializes DOM listeners. + * + * @private + * @returns {void} + */ +ResizeObserverController.prototype.connect_ = function () { + // Do nothing if running in a non-browser environment or if listeners + // have been already added. + if (!isBrowser || this.connected_) { + return; + } + + // Subscription to the "Transitionend" event is used as a workaround for + // delayed transitions. This way it's possible to capture at least the + // final state of an element. + document.addEventListener('transitionend', this.onTransitionEnd_); + + window.addEventListener('resize', this.refresh); + window.addEventListener('orientationchange', this.refresh); + + if (mutationObserverSupported) { + this.mutationsObserver_ = new MutationObserver(this.refresh); + + this.mutationsObserver_.observe(document, { + attributes: true, + childList: true, + characterData: true, + subtree: true + }); + } else { + document.addEventListener('DOMSubtreeModified', this.refresh); + + this.mutationEventsAdded_ = true; + } + + this.connected_ = true; +}; + +/** + * Removes DOM listeners. + * + * @private + * @returns {void} + */ +ResizeObserverController.prototype.disconnect_ = function () { + // Do nothing if running in a non-browser environment or if listeners + // have been already removed. + if (!isBrowser || !this.connected_) { + return; + } + + document.removeEventListener('transitionend', this.onTransitionEnd_); + window.removeEventListener('resize', this.refresh); + window.removeEventListener('orientationchange', this.refresh); + + if (this.mutationsObserver_) { + this.mutationsObserver_.disconnect(); + } + + if (this.mutationEventsAdded_) { + document.removeEventListener('DOMSubtreeModified', this.refresh); + } + + this.mutationsObserver_ = null; + this.mutationEventsAdded_ = false; + this.connected_ = false; +}; + +/** + * "Transitionend" event handler. + * + * @private + * @param {TransitionEvent} event + * @returns {void} + */ +ResizeObserverController.prototype.onTransitionEnd_ = function (ref) { + var propertyName = ref.propertyName; if ( propertyName === void 0 ) propertyName = ''; + + // Detect whether transition may affect dimensions of an element. + var isReflowProperty = transitionKeys.some(function (key) { + return !!~propertyName.indexOf(key); + }); + + if (isReflowProperty) { + this.refresh(); + } +}; + +/** + * Returns instance of the ResizeObserverController. + * + * @returns {ResizeObserverController} + */ +ResizeObserverController.getInstance = function () { + if (!this.instance_) { + this.instance_ = new ResizeObserverController(); + } + + return this.instance_; +}; + +ResizeObserverController.instance_ = null; + +/** + * Defines non-writable/enumerable properties of the provided target object. + * + * @param {Object} target - Object for which to define properties. + * @param {Object} props - Properties to be defined. + * @returns {Object} Target object. + */ +var defineConfigurable = (function (target, props) { + for (var i = 0, list = Object.keys(props); i < list.length; i += 1) { + var key = list[i]; + + Object.defineProperty(target, key, { + value: props[key], + enumerable: false, + writable: false, + configurable: true + }); + } + + return target; +}); + +/** + * Returns the global object associated with provided element. + * + * @param {Object} target + * @returns {Object} + */ +var getWindowOf = (function (target) { + // Assume that the element is an instance of Node, which means that it + // has the "ownerDocument" property from which we can retrieve a + // corresponding global object. + var ownerGlobal = target && target.ownerDocument && target.ownerDocument.defaultView; + + // Return the local global object if it's not possible extract one from + // provided element. + return ownerGlobal || global$1; +}); + +// Placeholder of an empty content rectangle. +var emptyRect = createRectInit(0, 0, 0, 0); + +/** + * Converts provided string to a number. + * + * @param {number|string} value + * @returns {number} + */ +function toFloat(value) { + return parseFloat(value) || 0; +} + +/** + * Extracts borders size from provided styles. + * + * @param {CSSStyleDeclaration} styles + * @param {...string} positions - Borders positions (top, right, ...) + * @returns {number} + */ +function getBordersSize(styles) { + var positions = [], len = arguments.length - 1; + while ( len-- > 0 ) positions[ len ] = arguments[ len + 1 ]; + + return positions.reduce(function (size, position) { + var value = styles['border-' + position + '-width']; + + return size + toFloat(value); + }, 0); +} + +/** + * Extracts paddings sizes from provided styles. + * + * @param {CSSStyleDeclaration} styles + * @returns {Object} Paddings box. + */ +function getPaddings(styles) { + var positions = ['top', 'right', 'bottom', 'left']; + var paddings = {}; + + for (var i = 0, list = positions; i < list.length; i += 1) { + var position = list[i]; + + var value = styles['padding-' + position]; + + paddings[position] = toFloat(value); + } + + return paddings; +} + +/** + * Calculates content rectangle of provided SVG element. + * + * @param {SVGGraphicsElement} target - Element content rectangle of which needs + * to be calculated. + * @returns {DOMRectInit} + */ +function getSVGContentRect(target) { + var bbox = target.getBBox(); + + return createRectInit(0, 0, bbox.width, bbox.height); +} + +/** + * Calculates content rectangle of provided HTMLElement. + * + * @param {HTMLElement} target - Element for which to calculate the content rectangle. + * @returns {DOMRectInit} + */ +function getHTMLElementContentRect(target) { + + var rect = target.getBoundingClientRect(); + return createRectInit(rect.left, rect.top, rect.width, rect.height); +} + +/** + * Checks whether provided element is a document element (). + * + * @param {Element} target - Element to be checked. + * @returns {boolean} + */ +function isDocumentElement(target) { + return target === getWindowOf(target).document.documentElement; +} + +/** + * Calculates an appropriate content rectangle for provided html or svg element. + * + * @param {Element} target - Element content rectangle of which needs to be calculated. + * @returns {DOMRectInit} + */ +function getContentRect(target) { + if (!isBrowser) { + return emptyRect; + } + + return getHTMLElementContentRect(target); +} + +/** + * Creates rectangle with an interface of the DOMRectReadOnly. + * Spec: https://drafts.fxtf.org/geometry/#domrectreadonly + * + * @param {DOMRectInit} rectInit - Object with rectangle's x/y coordinates and dimensions. + * @returns {DOMRectReadOnly} + */ +function createReadOnlyRect(ref) { + var x = ref.x; + var y = ref.y; + var width = ref.width; + var height = ref.height; + + // If DOMRectReadOnly is available use it as a prototype for the rectangle. + var Constr = typeof DOMRectReadOnly !== 'undefined' ? DOMRectReadOnly : Object; + var rect = Object.create(Constr.prototype); + + // Rectangle's properties are not writable and non-enumerable. + defineConfigurable(rect, { + x: x, y: y, width: width, height: height, + top: y, + right: x + width, + bottom: height + y, + left: x + }); + + return rect; +} + +/** + * Creates DOMRectInit object based on the provided dimensions and the x/y coordinates. + * Spec: https://drafts.fxtf.org/geometry/#dictdef-domrectinit + * + * @param {number} x - X coordinate. + * @param {number} y - Y coordinate. + * @param {number} width - Rectangle's width. + * @param {number} height - Rectangle's height. + * @returns {DOMRectInit} + */ +function createRectInit(x, y, width, height) { + return { x: x, y: y, width: width, height: height }; +} + +/** + * Class that is responsible for computations of the content rectangle of + * provided DOM element and for keeping track of it's changes. + */ +var ResizeObservation = function(target) { + this.broadcastWidth = 0; + this.broadcastHeight = 0; + this.contentRect_ = createRectInit(0, 0, 0, 0); + + this.target = target; +}; + +/** + * Updates content rectangle and tells whether it's width or height properties + * have changed since the last broadcast. + * + * @returns {boolean} + */ + + +/** + * Reference to the last observed content rectangle. + * + * @private {DOMRectInit} + */ + + +/** + * Broadcasted width of content rectangle. + * + * @type {number} + */ +ResizeObservation.prototype.isActive = function () { + var rect = getContentRect(this.target); + + this.contentRect_ = rect; + return rect.width !== this.broadcastWidth || rect.height !== this.broadcastHeight; +}; + +/** + * Updates 'broadcastWidth' and 'broadcastHeight' properties with a data + * from the corresponding properties of the last observed content rectangle. + * + * @returns {DOMRectInit} Last observed content rectangle. + */ +ResizeObservation.prototype.broadcastRect = function () { + var rect = this.contentRect_; + + this.broadcastWidth = rect.width; + this.broadcastHeight = rect.height; + + return rect; +}; + +var ResizeObserverEntry = function(target, rectInit) { + var contentRect = createReadOnlyRect(rectInit); + + // According to the specification following properties are not writable + // and are also not enumerable in the native implementation. + // + // Property accessors are not being used as they'd require to define a + // private WeakMap storage which may cause memory leaks in browsers that + // don't support this type of collections. + defineConfigurable(this, { target: target, contentRect: contentRect }); +}; + +var ResizeObserverSPI = function(callback, controller, callbackCtx) { + this.activeObservations_ = []; + this.observations_ = new MapShim(); + + if (typeof callback !== 'function') { + throw new TypeError('The callback provided as parameter 1 is not a function.'); + } + + this.callback_ = callback; + this.controller_ = controller; + this.callbackCtx_ = callbackCtx; +}; + +/** + * Starts observing provided element. + * + * @param {Element} target - Element to be observed. + * @returns {void} + */ + + +/** + * Registry of the ResizeObservation instances. + * + * @private {Map} + */ + + +/** + * Public ResizeObserver instance which will be passed to the callback + * function and used as a value of it's "this" binding. + * + * @private {ResizeObserver} + */ + +/** + * Collection of resize observations that have detected changes in dimensions + * of elements. + * + * @private {Array} + */ +ResizeObserverSPI.prototype.observe = function (target) { + if (!arguments.length) { + throw new TypeError('1 argument required, but only 0 present.'); + } + + // Do nothing if current environment doesn't have the Element interface. + if (typeof Element === 'undefined' || !(Element instanceof Object)) { + return; + } + + if (!(target instanceof getWindowOf(target).Element)) { + throw new TypeError('parameter 1 is not of type "Element".'); + } + + var observations = this.observations_; + + // Do nothing if element is already being observed. + if (observations.has(target)) { + return; + } + + observations.set(target, new ResizeObservation(target)); + + this.controller_.addObserver(this); + + // Force the update of observations. + this.controller_.refresh(); +}; + +/** + * Stops observing provided element. + * + * @param {Element} target - Element to stop observing. + * @returns {void} + */ +ResizeObserverSPI.prototype.unobserve = function (target) { + if (!arguments.length) { + throw new TypeError('1 argument required, but only 0 present.'); + } + + // Do nothing if current environment doesn't have the Element interface. + if (typeof Element === 'undefined' || !(Element instanceof Object)) { + return; + } + + if (!(target instanceof getWindowOf(target).Element)) { + throw new TypeError('parameter 1 is not of type "Element".'); + } + + var observations = this.observations_; + + // Do nothing if element is not being observed. + if (!observations.has(target)) { + return; + } + + observations.delete(target); + + if (!observations.size) { + this.controller_.removeObserver(this); + } +}; + +/** + * Stops observing all elements. + * + * @returns {void} + */ +ResizeObserverSPI.prototype.disconnect = function () { + this.clearActive(); + this.observations_.clear(); + this.controller_.removeObserver(this); +}; + +/** + * Collects observation instances the associated element of which has changed + * it's content rectangle. + * + * @returns {void} + */ +ResizeObserverSPI.prototype.gatherActive = function () { var this$1 = this; - this.clearActive(), this.observations_.forEach(function(observation) { - observation.isActive() && this$1.activeObservations_.push(observation) - }) - }, ResizeObserverSPI.prototype.broadcastActive = function() { - if (this.hasActive()) { - var ctx = this.callbackCtx_, - entries = this.activeObservations_.map(function(observation) { - return new ResizeObserverEntry(observation.target, observation.broadcastRect()) - }); - this.callback_.call(ctx, entries, ctx), this.clearActive() + + this.clearActive(); + + this.observations_.forEach(function (observation) { + if (observation.isActive()) { + this$1.activeObservations_.push(observation); } - }, ResizeObserverSPI.prototype.clearActive = function() { - this.activeObservations_.splice(0) - }, ResizeObserverSPI.prototype.hasActive = function() { - return this.activeObservations_.length > 0 + }); +}; + +/** + * Invokes initial callback function with a list of ResizeObserverEntry + * instances collected from active resize observations. + * + * @returns {void} + */ +ResizeObserverSPI.prototype.broadcastActive = function () { + // Do nothing if observer doesn't have active observations. + if (!this.hasActive()) { + return; + } + + var ctx = this.callbackCtx_; + + // Create ResizeObserverEntry instance for every active observation. + var entries = this.activeObservations_.map(function (observation) { + return new ResizeObserverEntry(observation.target, observation.broadcastRect()); + }); + + this.callback_.call(ctx, entries, ctx); + this.clearActive(); +}; + +/** + * Clears the collection of active observations. + * + * @returns {void} + */ +ResizeObserverSPI.prototype.clearActive = function () { + this.activeObservations_.splice(0); +}; + +/** + * Tells whether observer has active observations. + * + * @returns {boolean} + */ +ResizeObserverSPI.prototype.hasActive = function () { + return this.activeObservations_.length > 0; +}; + +// Registry of internal observers. If WeakMap is not available use current shim +// for the Map collection as it has all required methods and because WeakMap +// can't be fully polyfilled anyway. +var observers = typeof WeakMap !== 'undefined' ? new WeakMap() : new MapShim(); + +/** + * ResizeObserver API. Encapsulates the ResizeObserver SPI implementation + * exposing only those methods and properties that are defined in the spec. + */ +var ResizeObserver = function(callback) { + if (!(this instanceof ResizeObserver)) { + throw new TypeError('Cannot call a class as a function.'); + } + if (!arguments.length) { + throw new TypeError('1 argument required, but only 0 present.'); + } + + var controller = ResizeObserverController.getInstance(); + var observer = new ResizeObserverSPI(callback, controller, this); + + observers.set(this, observer); +}; + +// Expose public methods of ResizeObserver. +['observe', 'unobserve', 'disconnect'].forEach(function (method) { + ResizeObserver.prototype[method] = function () { + return (ref = observers.get(this))[method].apply(ref, arguments); + var ref; }; - var observers = "undefined" != typeof WeakMap ? new WeakMap : new MapShim, - ResizeObserver = function(callback) { - if (!(this instanceof ResizeObserver)) throw new TypeError("Cannot call a class as a function."); - if (!arguments.length) throw new TypeError("1 argument required, but only 0 present."); - var controller = ResizeObserverController.getInstance(), - observer = new ResizeObserverSPI(callback, controller, this); - observers.set(this, observer) - }; - return ["observe", "unobserve", "disconnect"].forEach(function(method) { - ResizeObserver.prototype[method] = function() { - return (ref = observers.get(this))[method].apply(ref, arguments); - var ref - } - }), - function() { - return void 0 !== global$1.ResizeObserver ? global$1.ResizeObserver : ResizeObserver - }() -}); \ No newline at end of file +}); + +var index = (function () { + // Export existing implementation if available. + if (typeof global$1.ResizeObserver !== 'undefined') { + return global$1.ResizeObserver; + } + + return ResizeObserver; +})(); + +return index; + +}))); diff --git a/src/bower_components/emby-webcomponents/router.js b/src/bower_components/emby-webcomponents/router.js index 00d38e1cdc..667aac28ad 100644 --- a/src/bower_components/emby-webcomponents/router.js +++ b/src/bower_components/emby-webcomponents/router.js @@ -1,416 +1,904 @@ -define(["loading", "globalize", "events", "viewManager", "layoutManager", "skinManager", "pluginManager", "backdrop", "browser", "pageJs", "appSettings", "apphost", "connectionManager"], function(loading, globalize, events, viewManager, layoutManager, skinManager, pluginManager, backdrop, browser, page, appSettings, appHost, connectionManager) { - "use strict"; +define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinManager', 'pluginManager', 'backdrop', 'browser', 'pageJs', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, layoutManager, skinManager, pluginManager, backdrop, browser, page, appSettings, appHost, connectionManager) { + 'use strict'; + + var appRouter = { + showLocalLogin: function (serverId, manualLogin) { + + var pageName = manualLogin ? 'manuallogin' : 'login'; + + show('/startup/' + pageName + '.html?serverid=' + serverId); + }, + showSelectServer: function () { + show('/startup/selectserver.html'); + }, + showWelcome: function () { + show('/startup/welcome.html'); + }, + showConnectLogin: function () { + show('/startup/connectlogin.html'); + }, + showSettings: function () { + show('/settings/settings.html'); + }, + showSearch: function () { + skinManager.getCurrentSkin().search(); + }, + showGenre: function (options) { + skinManager.getCurrentSkin().showGenre(options); + }, + showGuide: function () { + skinManager.getCurrentSkin().showGuide({ + serverId: connectionManager.currentApiClient().serverId() + }); + }, + showLiveTV: function () { + skinManager.getCurrentSkin().showLiveTV({ + serverId: connectionManager.currentApiClient().serverId() + }); + }, + showRecordedTV: function () { + skinManager.getCurrentSkin().showRecordedTV(); + }, + showFavorites: function () { + skinManager.getCurrentSkin().showFavorites(); + }, + showNowPlaying: function () { + skinManager.getCurrentSkin().showNowPlaying(); + } + }; function beginConnectionWizard() { - backdrop.clear(), loading.show(), connectionManager.connect({ + + backdrop.clear(); + + loading.show(); + + connectionManager.connect({ + enableAutoLogin: appSettings.enableAutoLogin() - }).then(function(result) { - handleConnectionResult(result, loading) - }) + + }).then(function (result) { + handleConnectionResult(result, loading); + }); } function handleConnectionResult(result, loading) { + switch (result.State) { - case "SignedIn": - loading.hide(), skinManager.loadUserSkin(); + + case 'SignedIn': + { + loading.hide(); + skinManager.loadUserSkin(); + } break; - case "ServerSignIn": - result.ApiClient.getPublicUsers().then(function(users) { - users.length ? appRouter.showLocalLogin(result.Servers[0].Id) : appRouter.showLocalLogin(result.Servers[0].Id, !0) - }); + case 'ServerSignIn': + { + result.ApiClient.getPublicUsers().then(function (users) { + + if (users.length) { + appRouter.showLocalLogin(result.Servers[0].Id); + } else { + appRouter.showLocalLogin(result.Servers[0].Id, true); + } + }); + } break; - case "ServerSelection": - appRouter.showSelectServer(); + case 'ServerSelection': + { + appRouter.showSelectServer(); + } break; - case "ConnectSignIn": - appRouter.showWelcome(); + case 'ConnectSignIn': + { + appRouter.showWelcome(); + } + break; + case 'ServerUpdateNeeded': + { + require(['alert'], function (alert) { + alert({ + + text: globalize.translate('sharedcomponents#ServerUpdateNeeded', 'https://emby.media'), + html: globalize.translate('sharedcomponents#ServerUpdateNeeded', 'https://emby.media') + + }).then(function () { + appRouter.showSelectServer(); + }); + }); + } + break; + default: break; - case "ServerUpdateNeeded": - require(["alert"], function(alert) { - alert({ - text: globalize.translate("sharedcomponents#ServerUpdateNeeded", "https://github.com/jellyfin/jellyfin"), - html: globalize.translate("sharedcomponents#ServerUpdateNeeded", 'https://github.com/jellyfin/jellyfin') - }).then(function() { - appRouter.showSelectServer() - }) - }) } } function loadContentUrl(ctx, next, route, request) { + var url; - url = route.contentPath && "function" == typeof route.contentPath ? route.contentPath(ctx.querystring) : route.contentPath || route.path, -1 === url.indexOf("://") && (0 !== url.indexOf("/") && (url = "/" + url), url = baseUrl() + url), ctx.querystring && route.enableContentQueryString && (url += "?" + ctx.querystring), require(["text!" + url], function(html) { - loadContent(ctx, route, html, request) - }) + + if (route.contentPath && typeof (route.contentPath) === 'function') { + url = route.contentPath(ctx.querystring); + } else { + url = route.contentPath || route.path; + } + + if (url.indexOf('://') === -1) { + + // Put a slash at the beginning but make sure to avoid a double slash + if (url.indexOf('/') !== 0) { + + url = '/' + url; + } + + url = baseUrl() + url; + } + + if (ctx.querystring && route.enableContentQueryString) { + url += '?' + ctx.querystring; + } + + require(['text!' + url], function (html) { + + loadContent(ctx, route, html, request); + }); } function handleRoute(ctx, next, route) { - authenticate(ctx, route, function() { - initRoute(ctx, next, route) - }) + + authenticate(ctx, route, function () { + initRoute(ctx, next, route); + }); } function initRoute(ctx, next, route) { - var onInitComplete = function(controllerFactory) { - sendRouteToViewManager(ctx, next, route, controllerFactory) + + var onInitComplete = function (controllerFactory) { + sendRouteToViewManager(ctx, next, route, controllerFactory); }; - require(route.dependencies || [], function() { - route.controller ? require([route.controller], onInitComplete) : onInitComplete() - }) + + require(route.dependencies || [], function () { + + if (route.controller) { + require([route.controller], onInitComplete); + } else { + onInitComplete(); + } + }); } function cancelCurrentLoadRequest() { var currentRequest = currentViewLoadRequest; - currentRequest && (currentRequest.cancel = !0) + if (currentRequest) { + currentRequest.cancel = true; + } } + var currentViewLoadRequest; function sendRouteToViewManager(ctx, next, route, controllerFactory) { - if (isDummyBackToHome && "home" === route.type) return void(isDummyBackToHome = !1); + + if (isDummyBackToHome && route.type === 'home') { + isDummyBackToHome = false; + return; + } + cancelCurrentLoadRequest(); - var isBackNav = ctx.isBack, - currentRequest = { - url: baseUrl() + ctx.path, - transition: route.transition, - isBack: isBackNav, - state: ctx.state, - type: route.type, - fullscreen: route.fullscreen, - controllerFactory: controllerFactory, - options: { - supportsThemeMedia: route.supportsThemeMedia || !1, - enableMediaControl: !1 !== route.enableMediaControl - }, - autoFocus: route.autoFocus - }; - currentViewLoadRequest = currentRequest; - var onNewViewNeeded = function() { - "string" == typeof route.path ? loadContentUrl(ctx, next, route, currentRequest) : next() + + var isBackNav = ctx.isBack; + + var currentRequest = { + url: baseUrl() + ctx.path, + transition: route.transition, + isBack: isBackNav, + state: ctx.state, + type: route.type, + fullscreen: route.fullscreen, + controllerFactory: controllerFactory, + options: { + supportsThemeMedia: route.supportsThemeMedia || false, + enableMediaControl: route.enableMediaControl !== false + }, + autoFocus: route.autoFocus }; - if (!isBackNav) return void onNewViewNeeded(); - viewManager.tryRestoreView(currentRequest, function() { + currentViewLoadRequest = currentRequest; + + var onNewViewNeeded = function () { + if (typeof route.path === 'string') { + + loadContentUrl(ctx, next, route, currentRequest); + + } else { + // ? TODO + next(); + } + }; + + if (!isBackNav) { + // Don't force a new view for home due to the back menu + //if (route.type !== 'home') { + onNewViewNeeded(); + return; + //} + } + viewManager.tryRestoreView(currentRequest, function () { + + // done currentRouteInfo = { route: route, path: ctx.path + }; + + }).catch(function (result) { + + if (!result || !result.cancelled) { + onNewViewNeeded(); } - }).catch(function(result) { - result && result.cancelled || onNewViewNeeded() - }) + }); } + var msgTimeout; + var forcedLogoutMsg; function onForcedLogoutMessageTimeout() { + var msg = forcedLogoutMsg; - forcedLogoutMsg = null, msg && require(["alert"], function(alert) { - alert(msg) - }) + forcedLogoutMsg = null; + + if (msg) { + require(['alert'], function (alert) { + alert(msg); + }); + } } function showForcedLogoutMessage(msg) { - forcedLogoutMsg = msg, msgTimeout && clearTimeout(msgTimeout), msgTimeout = setTimeout(onForcedLogoutMessageTimeout, 100) + + forcedLogoutMsg = msg; + if (msgTimeout) { + clearTimeout(msgTimeout); + } + + msgTimeout = setTimeout(onForcedLogoutMessageTimeout, 100); } function onRequestFail(e, data) { + var apiClient = this; - if (401 === data.status && "ParentalControl" === data.errorCode) { - !currentRouteInfo || (currentRouteInfo.route.anonymous || currentRouteInfo.route.startup) || (showForcedLogoutMessage(globalize.translate("sharedcomponents#AccessRestrictedTryAgainLater")), connectionManager.isLoggedIntoConnect() ? appRouter.showConnectLogin() : appRouter.showLocalLogin(apiClient.serverId())) + + if (data.status === 401) { + if (data.errorCode === "ParentalControl") { + + var isCurrentAllowed = currentRouteInfo ? (currentRouteInfo.route.anonymous || currentRouteInfo.route.startup) : true; + + // Bounce to the login screen, but not if a password entry fails, obviously + if (!isCurrentAllowed) { + + showForcedLogoutMessage(globalize.translate('sharedcomponents#AccessRestrictedTryAgainLater')); + + if (connectionManager.isLoggedIntoConnect()) { + appRouter.showConnectLogin(); + } else { + appRouter.showLocalLogin(apiClient.serverId()); + } + } + + } } } function onBeforeExit(e) { - browser.web0s && page.restorePreviousState() + + if (browser.web0s) { + page.restorePreviousState(); + } } function normalizeImageOptions(options) { - var setQuality, scaleFactor = browser.tv ? .8 : 1; - if (options.maxWidth && (options.maxWidth = Math.round(options.maxWidth * scaleFactor), setQuality = !0), options.width && (options.width = Math.round(options.width * scaleFactor), setQuality = !0), options.maxHeight && (options.maxHeight = Math.round(options.maxHeight * scaleFactor), setQuality = !0), options.height && (options.height = Math.round(options.height * scaleFactor), setQuality = !0), setQuality) { - var quality = 100, - type = options.type || "Primary"; - quality = browser.tv || browser.slow ? browser.chrome ? "Primary" === type ? 40 : 50 : "Backdrop" === type ? 60 : 50 : "Backdrop" === type ? 70 : 90, options.quality = quality + + var scaleFactor = browser.tv ? 0.8 : 1; + + var setQuality; + if (options.maxWidth) { + options.maxWidth = Math.round(options.maxWidth * scaleFactor); + setQuality = true; + } + + if (options.width) { + options.width = Math.round(options.width * scaleFactor); + setQuality = true; + } + + if (options.maxHeight) { + options.maxHeight = Math.round(options.maxHeight * scaleFactor); + setQuality = true; + } + + if (options.height) { + options.height = Math.round(options.height * scaleFactor); + setQuality = true; + } + + if (setQuality) { + + var quality = 100; + + var type = options.type || 'Primary'; + + if (browser.tv || browser.slow) { + + if (browser.chrome) { + // webp support + quality = type === 'Primary' ? 40 : 50; + } else { + quality = type === 'Backdrop' ? 60 : 50; + } + } else { + quality = type === 'Backdrop' ? 70 : 90; + } + + options.quality = quality; } } function getMaxBandwidth() { + if (navigator.connection) { + var max = navigator.connection.downlinkMax; - if (max && max > 0 && max < Number.POSITIVE_INFINITY) return max /= 8, max *= 1e6, max *= .7, max = parseInt(max) + if (max && max > 0 && max < Number.POSITIVE_INFINITY) { + + max /= 8; + max *= 1000000; + max *= 0.7; + max = parseInt(max); + return max; + } } - return null + + return null; } function getMaxBandwidthIOS() { - return 8e5 + return 800000; } function onApiClientCreated(e, newApiClient) { - newApiClient.normalizeImageOptions = normalizeImageOptions, browser.iOS ? newApiClient.getMaxBandwidth = getMaxBandwidthIOS : newApiClient.getMaxBandwidth = getMaxBandwidth, events.off(newApiClient, "requestfail", onRequestFail), events.on(newApiClient, "requestfail", onRequestFail) + + newApiClient.normalizeImageOptions = normalizeImageOptions; + + if (browser.iOS) { + newApiClient.getMaxBandwidth = getMaxBandwidthIOS; + } else { + newApiClient.getMaxBandwidth = getMaxBandwidth; + } + + events.off(newApiClient, 'requestfail', onRequestFail); + events.on(newApiClient, 'requestfail', onRequestFail); } function initApiClient(apiClient) { - onApiClientCreated({}, apiClient) + + onApiClientCreated({}, apiClient); } function initApiClients() { - connectionManager.getApiClients().forEach(initApiClient), events.on(connectionManager, "apiclientcreated", onApiClientCreated) + + connectionManager.getApiClients().forEach(initApiClient); + + events.on(connectionManager, 'apiclientcreated', onApiClientCreated); } function onAppResume() { var apiClient = connectionManager.currentApiClient(); - apiClient && apiClient.ensureWebSocket() + + if (apiClient) { + apiClient.ensureWebSocket(); + } } + var firstConnectionResult; function start(options) { - loading.show(), initApiClients(), events.on(appHost, "beforeexit", onBeforeExit), events.on(appHost, "resume", onAppResume), connectionManager.connect({ + + loading.show(); + + initApiClients(); + + events.on(appHost, 'beforeexit', onBeforeExit); + events.on(appHost, 'resume', onAppResume); + + connectionManager.connect({ + enableAutoLogin: appSettings.enableAutoLogin() - }).then(function(result) { - firstConnectionResult = result, loading.hide(), options = options || {}, page({ - click: !1 !== options.click, - hashbang: !1 !== options.hashbang, + + }).then(function (result) { + + firstConnectionResult = result; + + loading.hide(); + + options = options || {}; + + page({ + click: options.click !== false, + hashbang: options.hashbang !== false, enableHistory: enableHistory() - }) - }) + }); + }); } function enableHistory() { - return !browser.xboxOne && !browser.orsay + + //if (browser.edgeUwp) { + // return false; + //} + + // shows status bar on navigation + if (browser.xboxOne) { + return false; + } + + // Does not support history + if (browser.orsay) { + return false; + } + + return true; } function enableNativeHistory() { - return page.enableNativeHistory() + return page.enableNativeHistory(); } function authenticate(ctx, route, callback) { + var firstResult = firstConnectionResult; - if (firstResult && (firstConnectionResult = null, "SignedIn" !== firstResult.State && !route.anonymous)) return void handleConnectionResult(firstResult, loading); - var apiClient = connectionManager.currentApiClient(), - pathname = ctx.pathname.toLowerCase(); - console.log("appRouter - processing path request " + pathname); - var isCurrentRouteStartup = !currentRouteInfo || currentRouteInfo.route.startup, - shouldExitApp = ctx.isBack && route.isDefaultRoute && isCurrentRouteStartup; - if (!(shouldExitApp || apiClient && apiClient.isLoggedIn() || route.anonymous)) return console.log("appRouter - route does not allow anonymous access, redirecting to login"), void beginConnectionWizard(); - if (shouldExitApp) { - if (appHost.supports("exit")) return void appHost.exit() - } else { - if (apiClient && apiClient.isLoggedIn()) { - if (console.log("appRouter - user is authenticated"), ctx.isBack && (route.isDefaultRoute || route.startup) && !isCurrentRouteStartup) return void handleBackToDefault(); - if (route.isDefaultRoute) return console.log("appRouter - loading skin home page"), void loadUserSkinWithOptions(ctx); - if (route.roles) return void validateRoles(apiClient, route.roles).then(function() { - callback() - }, beginConnectionWizard) + if (firstResult) { + + firstConnectionResult = null; + + if (firstResult.State !== 'SignedIn' && !route.anonymous) { + + handleConnectionResult(firstResult, loading); + return; } - console.log("appRouter - proceeding to " + pathname), callback() } + + var apiClient = connectionManager.currentApiClient(); + var pathname = ctx.pathname.toLowerCase(); + + console.log('appRouter - processing path request ' + pathname); + + var isCurrentRouteStartup = currentRouteInfo ? currentRouteInfo.route.startup : true; + var shouldExitApp = ctx.isBack && route.isDefaultRoute && isCurrentRouteStartup; + + if (!shouldExitApp && (!apiClient || !apiClient.isLoggedIn()) && !route.anonymous) { + console.log('appRouter - route does not allow anonymous access, redirecting to login'); + beginConnectionWizard(); + return; + } + + if (shouldExitApp) { + if (appHost.supports('exit')) { + appHost.exit(); + return; + } + return; + } + + if (apiClient && apiClient.isLoggedIn()) { + + console.log('appRouter - user is authenticated'); + + if (ctx.isBack && (route.isDefaultRoute || route.startup) && !isCurrentRouteStartup) { + handleBackToDefault(); + return; + } + else if (route.isDefaultRoute) { + console.log('appRouter - loading skin home page'); + loadUserSkinWithOptions(ctx); + return; + } else if (route.roles) { + + validateRoles(apiClient, route.roles).then(function () { + + callback(); + + }, beginConnectionWizard); + return; + } + } + + console.log('appRouter - proceeding to ' + pathname); + callback(); } function loadUserSkinWithOptions(ctx) { - require(["queryString"], function(queryString) { + + require(['queryString'], function (queryString) { + + //var url = options.url; + //var index = url.indexOf('?'); var params = queryString.parse(ctx.querystring); + skinManager.loadUserSkin({ start: params.start - }) - }) + }); + }); } function validateRoles(apiClient, roles) { - return Promise.all(roles.split(",").map(function(role) { - return validateRole(apiClient, role) - })) + + return Promise.all(roles.split(',').map(function (role) { + return validateRole(apiClient, role); + })); } function validateRole(apiClient, role) { - return "admin" === role ? apiClient.getCurrentUser().then(function(user) { - return user.Policy.IsAdministrator ? Promise.resolve() : Promise.reject() - }) : Promise.resolve() + + if (role === 'admin') { + + return apiClient.getCurrentUser().then(function (user) { + if (user.Policy.IsAdministrator) { + return Promise.resolve(); + } + return Promise.reject(); + }); + } + + // Unknown role + return Promise.resolve(); } + var isHandlingBackToDefault; + var isDummyBackToHome; + function handleBackToDefault() { - if (!appHost.supports("exitmenu") && appHost.supports("exit")) return void appHost.exit(); - isDummyBackToHome = !0, skinManager.loadUserSkin(), isHandlingBackToDefault || skinManager.getCurrentSkin().showBackMenu().then(function() { - isHandlingBackToDefault = !1 - }) + + if (!appHost.supports('exitmenu') && appHost.supports('exit')) { + appHost.exit(); + return; + } + + isDummyBackToHome = true; + skinManager.loadUserSkin(); + + if (isHandlingBackToDefault) { + return; + } + + // This must result in a call to either + // skinManager.loadUserSkin(); + // Logout + // Or exit app + skinManager.getCurrentSkin().showBackMenu().then(function () { + + isHandlingBackToDefault = false; + }); } function loadContent(ctx, route, html, request) { - html = globalize.translateDocument(html, route.dictionary), request.view = html, viewManager.loadView(request), currentRouteInfo = { + + html = globalize.translateDocument(html, route.dictionary); + request.view = html; + + viewManager.loadView(request); + + currentRouteInfo = { route: route, path: ctx.path - }, ctx.handled = !0 + }; + //next(); + + ctx.handled = true; } function getRequestFile() { - var path = self.location.pathname || "", - index = path.lastIndexOf("/"); - return path = -1 !== index ? path.substring(index) : "/" + path, path && "/" !== path || (path = "/index.html"), path + var path = self.location.pathname || ''; + + var index = path.lastIndexOf('/'); + if (index !== -1) { + path = path.substring(index); + } else { + path = '/' + path; + } + + if (!path || path === '/') { + path = '/index.html'; + } + + return path; } function endsWith(str, srch) { - return str.lastIndexOf(srch) === srch.length - 1 + + return str.lastIndexOf(srch) === srch.length - 1; } + var baseRoute = self.location.href.split('?')[0].replace(getRequestFile(), ''); + // support hashbang + baseRoute = baseRoute.split('#')[0]; + if (endsWith(baseRoute, '/') && !endsWith(baseRoute, '://')) { + baseRoute = baseRoute.substring(0, baseRoute.length - 1); + } function baseUrl() { - return baseRoute + return baseRoute; } function getHandler(route) { - return function(ctx, next) { - handleRoute(ctx, next, route) - } + return function (ctx, next) { + handleRoute(ctx, next, route); + }; } function getWindowLocationSearch(win) { - var currentPath = currentRouteInfo ? currentRouteInfo.path || "" : "", - index = currentPath.indexOf("?"), - search = ""; - return -1 !== index && (search = currentPath.substring(index)), search || "" + + var currentPath = currentRouteInfo ? (currentRouteInfo.path || '') : ''; + + var index = currentPath.indexOf('?'); + var search = ''; + + if (index !== -1) { + search = currentPath.substring(index); + } + + return search || ''; } function param(name, url) { - name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); - var regexS = "[\\?&]" + name + "=([^&#]*)", - regex = new RegExp(regexS, "i"), - results = regex.exec(url || getWindowLocationSearch()); - return null == results ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")) + name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); + var regexS = "[\\?&]" + name + "=([^&#]*)"; + var regex = new RegExp(regexS, "i"); + + var results = regex.exec(url || getWindowLocationSearch()); + if (results == null) { + return ""; + } else { + return decodeURIComponent(results[1].replace(/\+/g, " ")); + } } function back() { - page.back() + + page.back(); } function canGoBack() { + var curr = current(); - return !!curr && ("home" !== curr.type && page.canGoBack()) - } + if (!curr) { + return false; + } + + if (curr.type === 'home') { + return false; + } + return page.canGoBack(); + } function show(path, options) { - 0 !== path.indexOf("/") && -1 === path.indexOf("://") && (path = "/" + path); + + if (path.indexOf('/') !== 0 && path.indexOf('://') === -1) { + path = '/' + path; + } + var baseRoute = baseUrl(); - return path = path.replace(baseRoute, ""), currentRouteInfo && currentRouteInfo.path === path && "home" !== currentRouteInfo.route.type ? (loading.hide(), Promise.resolve()) : new Promise(function(resolve, reject) { - resolveOnNextShow = resolve, page.show(path, options) - }) + path = path.replace(baseRoute, ''); + + if (currentRouteInfo && currentRouteInfo.path === path) { + + // can't use this with home right now due to the back menu + if (currentRouteInfo.route.type !== 'home') { + loading.hide(); + return Promise.resolve(); + } + } + + return new Promise(function (resolve, reject) { + + resolveOnNextShow = resolve; + page.show(path, options); + }); } + var resolveOnNextShow; + document.addEventListener('viewshow', function () { + var resolve = resolveOnNextShow; + if (resolve) { + resolveOnNextShow = null; + resolve(); + } + }); + + var currentRouteInfo; function current() { - return currentRouteInfo ? currentRouteInfo.route : null + return currentRouteInfo ? currentRouteInfo.route : null; } function goHome() { + var skin = skinManager.getCurrentSkin(); + if (skin.getHomeRoute) { var homePath = skin.getHomeRoute(); - return show(pluginManager.mapRoute(skin, homePath)) + return show(pluginManager.mapRoute(skin, homePath)); + } else { + var homeRoute = skin.getRoutes().filter(function (r) { + return r.type === 'home'; + })[0]; + + return show(pluginManager.mapRoute(skin, homeRoute)); } - var homeRoute = skin.getRoutes().filter(function(r) { - return "home" === r.type - })[0]; - return show(pluginManager.mapRoute(skin, homeRoute)) } function getRouteUrl(item, options) { - return "downloads" === item ? "offline/offline.html" : "managedownloads" === item ? "offline/managedownloads.html" : "settings" === item ? "settings/settings.html" : skinManager.getCurrentSkin().getRouteUrl(item, options) + + if (item === 'downloads') { + return 'offline/offline.html'; + } + if (item === 'managedownloads') { + return 'offline/managedownloads.html'; + } + if (item === 'settings') { + return 'settings/settings.html'; + } + + return skinManager.getCurrentSkin().getRouteUrl(item, options); } function showItem(item, serverId, options) { - if ("string" == typeof item) { + + if (typeof (item) === 'string') { var apiClient = serverId ? connectionManager.getApiClient(serverId) : connectionManager.currentApiClient(); - apiClient.getItem(apiClient.getCurrentUserId(), item).then(function(item) { - appRouter.showItem(item, options) - }) + apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (item) { + appRouter.showItem(item, options); + }); } else { - 2 === arguments.length && (options = arguments[1]); + + if (arguments.length === 2) { + options = arguments[1]; + } + var url = appRouter.getRouteUrl(item, options); appRouter.show(url, { item: item - }) + }); } } function setTitle(title) { - skinManager.getCurrentSkin().setTitle(title) + skinManager.getCurrentSkin().setTitle(title); } function showVideoOsd() { - var skin = skinManager.getCurrentSkin(), - homeRoute = skin.getRoutes().filter(function(r) { - return "video-osd" === r.type - })[0]; - return show(pluginManager.mapRoute(skin, homeRoute)) + var skin = skinManager.getCurrentSkin(); + + var homeRoute = skin.getRoutes().filter(function (r) { + return r.type === 'video-osd'; + })[0]; + + return show(pluginManager.mapRoute(skin, homeRoute)); } + var allRoutes = []; + function addRoute(path, newRoute) { - page(path, getHandler(newRoute)), allRoutes.push(newRoute) + + page(path, getHandler(newRoute)); + allRoutes.push(newRoute); } function getRoutes() { - return allRoutes + return allRoutes; } + var backdropContainer; + var backgroundContainer; function setTransparency(level) { - backdropContainer || (backdropContainer = document.querySelector(".backdropContainer")), backgroundContainer || (backgroundContainer = document.querySelector(".backgroundContainer")), "full" === level || 2 === level ? (backdrop.clear(!0), document.documentElement.classList.add("transparentDocument"), backgroundContainer.classList.add("backgroundContainer-transparent"), backdropContainer.classList.add("hide")) : "backdrop" === level || 1 === level ? (backdrop.externalBackdrop(!0), document.documentElement.classList.add("transparentDocument"), backgroundContainer.classList.add("backgroundContainer-transparent"), backdropContainer.classList.add("hide")) : (backdrop.externalBackdrop(!1), document.documentElement.classList.remove("transparentDocument"), backgroundContainer.classList.remove("backgroundContainer-transparent"), backdropContainer.classList.remove("hide")) + + if (!backdropContainer) { + backdropContainer = document.querySelector('.backdropContainer'); + } + if (!backgroundContainer) { + backgroundContainer = document.querySelector('.backgroundContainer'); + } + + if (level === 'full' || level === 2) { + backdrop.clear(true); + document.documentElement.classList.add('transparentDocument'); + backgroundContainer.classList.add('backgroundContainer-transparent'); + backdropContainer.classList.add('hide'); + } + else if (level === 'backdrop' || level === 1) { + backdrop.externalBackdrop(true); + document.documentElement.classList.add('transparentDocument'); + backgroundContainer.classList.add('backgroundContainer-transparent'); + backdropContainer.classList.add('hide'); + } else { + backdrop.externalBackdrop(false); + document.documentElement.classList.remove('transparentDocument'); + backgroundContainer.classList.remove('backgroundContainer-transparent'); + backdropContainer.classList.remove('hide'); + } } function pushState(state, title, url) { - state.navigate = !1, page.pushState(state, title, url) + + state.navigate = false; + + page.pushState(state, title, url); + } + + function setBaseRoute() { + var baseRoute = self.location.pathname.replace(getRequestFile(), ''); + if (baseRoute.lastIndexOf('/') === baseRoute.length - 1) { + baseRoute = baseRoute.substring(0, baseRoute.length - 1); + } + + console.log('Setting page base to ' + baseRoute); + + page.base(baseRoute); + } + + setBaseRoute(); + + function syncNow() { + require(['localsync'], function (localSync) { + localSync.sync(); + }); } function invokeShortcut(id) { - 0 === id.indexOf("library-") ? (id = id.replace("library-", ""), id = id.split("_"), appRouter.showItem(id[0], id[1])) : 0 === id.indexOf("item-") ? (id = id.replace("item-", ""), id = id.split("_"), appRouter.showItem(id[0], id[1])) : (id = id.split("_"), appRouter.show(appRouter.getRouteUrl(id[0], { - serverId: id[1] - }))) + + if (id.indexOf('library-') === 0) { + + id = id.replace('library-', ''); + + id = id.split('_'); + + appRouter.showItem(id[0], id[1]); + + } else if (id.indexOf('item-') === 0) { + + id = id.replace('item-', ''); + + id = id.split('_'); + + appRouter.showItem(id[0], id[1]); + + } else { + + id = id.split('_'); + + appRouter.show(appRouter.getRouteUrl(id[0], { + serverId: id[1] + })); + } } - var currentViewLoadRequest, msgTimeout, forcedLogoutMsg, firstConnectionResult, isHandlingBackToDefault, isDummyBackToHome, appRouter = { - showLocalLogin: function(serverId, manualLogin) { - show("/startup/" + (manualLogin ? "manuallogin" : "login") + ".html?serverid=" + serverId) - }, - showSelectServer: function() { - show("/startup/selectserver.html") - }, - showWelcome: function() { - show("/startup/welcome.html") - }, - showConnectLogin: function() { - show("/startup/connectlogin.html") - }, - showSettings: function() { - show("/settings/settings.html") - }, - showSearch: function() { - skinManager.getCurrentSkin().search() - }, - showGenre: function(options) { - skinManager.getCurrentSkin().showGenre(options) - }, - showGuide: function() { - skinManager.getCurrentSkin().showGuide({ - serverId: connectionManager.currentApiClient().serverId() - }) - }, - showLiveTV: function() { - skinManager.getCurrentSkin().showLiveTV({ - serverId: connectionManager.currentApiClient().serverId() - }) - }, - showRecordedTV: function() { - skinManager.getCurrentSkin().showRecordedTV() - }, - showFavorites: function() { - skinManager.getCurrentSkin().showFavorites() - }, - showNowPlaying: function() { - skinManager.getCurrentSkin().showNowPlaying() - } - }, - baseRoute = self.location.href.split("?")[0].replace(getRequestFile(), ""); - baseRoute = baseRoute.split("#")[0], endsWith(baseRoute, "/") && !endsWith(baseRoute, "://") && (baseRoute = baseRoute.substring(0, baseRoute.length - 1)); - var resolveOnNextShow; - document.addEventListener("viewshow", function() { - var resolve = resolveOnNextShow; - resolve && (resolveOnNextShow = null, resolve()) - }); - var currentRouteInfo, backdropContainer, backgroundContainer, allRoutes = []; - return function() { - var baseRoute = self.location.pathname.replace(getRequestFile(), ""); - baseRoute.lastIndexOf("/") === baseRoute.length - 1 && (baseRoute = baseRoute.substring(0, baseRoute.length - 1)), console.log("Setting page base to " + baseRoute), page.base(baseRoute) - }(), appRouter.addRoute = addRoute, appRouter.param = param, appRouter.back = back, appRouter.show = show, appRouter.start = start, appRouter.baseUrl = baseUrl, appRouter.canGoBack = canGoBack, appRouter.current = current, appRouter.beginConnectionWizard = beginConnectionWizard, appRouter.goHome = goHome, appRouter.showItem = showItem, appRouter.setTitle = setTitle, appRouter.setTransparency = setTransparency, appRouter.getRoutes = getRoutes, appRouter.getRouteUrl = getRouteUrl, appRouter.pushState = pushState, appRouter.enableNativeHistory = enableNativeHistory, appRouter.showVideoOsd = showVideoOsd, appRouter.handleAnchorClick = page.handleAnchorClick, appRouter.TransparencyLevel = { + + appRouter.addRoute = addRoute; + appRouter.param = param; + appRouter.back = back; + appRouter.show = show; + appRouter.start = start; + appRouter.baseUrl = baseUrl; + appRouter.canGoBack = canGoBack; + appRouter.current = current; + appRouter.beginConnectionWizard = beginConnectionWizard; + appRouter.goHome = goHome; + appRouter.showItem = showItem; + appRouter.setTitle = setTitle; + appRouter.setTransparency = setTransparency; + appRouter.getRoutes = getRoutes; + appRouter.getRouteUrl = getRouteUrl; + appRouter.pushState = pushState; + appRouter.enableNativeHistory = enableNativeHistory; + appRouter.showVideoOsd = showVideoOsd; + appRouter.handleAnchorClick = page.handleAnchorClick; + appRouter.TransparencyLevel = { None: 0, Backdrop: 1, Full: 2 - }, appRouter.invokeShortcut = invokeShortcut, appRouter + }; + appRouter.invokeShortcut = invokeShortcut; + + return appRouter; }); diff --git a/src/bower_components/emby-webcomponents/sanitizefilename.js b/src/bower_components/emby-webcomponents/sanitizefilename.js index fc8e3a8a64..fbc387836b 100644 --- a/src/bower_components/emby-webcomponents/sanitizefilename.js +++ b/src/bower_components/emby-webcomponents/sanitizefilename.js @@ -1,36 +1,100 @@ -define([], function() { - "use strict"; +// From https://github.com/parshap/node-sanitize-filename + +define([], function () { + 'use strict'; + + var illegalRe = /[\/\?<>\\:\*\|":]/g; + var controlRe = /[\x00-\x1f\x80-\x9f]/g; + var reservedRe = /^\.+$/; + var windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i; + var windowsTrailingRe = /[\. ]+$/; function isHighSurrogate(codePoint) { - return codePoint >= 55296 && codePoint <= 56319 + return codePoint >= 0xd800 && codePoint <= 0xdbff; } function isLowSurrogate(codePoint) { - return codePoint >= 56320 && codePoint <= 57343 + return codePoint >= 0xdc00 && codePoint <= 0xdfff; } function getByteLength(string) { - if ("string" != typeof string) throw new Error("Input must be string"); - for (var charLength = string.length, byteLength = 0, codePoint = null, prevCodePoint = null, i = 0; i < charLength; i++) codePoint = string.charCodeAt(i), isLowSurrogate(codePoint) ? null != prevCodePoint && isHighSurrogate(prevCodePoint) ? byteLength += 1 : byteLength += 3 : codePoint <= 127 ? byteLength += 1 : codePoint >= 128 && codePoint <= 2047 ? byteLength += 2 : codePoint >= 2048 && codePoint <= 65535 && (byteLength += 3), prevCodePoint = codePoint; - return byteLength + if (typeof string !== "string") { + throw new Error("Input must be string"); + } + + var charLength = string.length; + var byteLength = 0; + var codePoint = null; + var prevCodePoint = null; + for (var i = 0; i < charLength; i++) { + codePoint = string.charCodeAt(i); + // handle 4-byte non-BMP chars + // low surrogate + if (isLowSurrogate(codePoint)) { + // when parsing previous hi-surrogate, 3 is added to byteLength + if (prevCodePoint != null && isHighSurrogate(prevCodePoint)) { + byteLength += 1; + } + else { + byteLength += 3; + } + } + else if (codePoint <= 0x7f) { + byteLength += 1; + } + else if (codePoint >= 0x80 && codePoint <= 0x7ff) { + byteLength += 2; + } + else if (codePoint >= 0x800 && codePoint <= 0xffff) { + byteLength += 3; + } + prevCodePoint = codePoint; + } + + return byteLength; } function truncate(string, byteLength) { - if ("string" != typeof string) throw new Error("Input must be string"); - for (var codePoint, segment, charLength = string.length, curByteLength = 0, i = 0; i < charLength; i += 1) { - if (codePoint = string.charCodeAt(i), segment = string[i], isHighSurrogate(codePoint) && isLowSurrogate(string.charCodeAt(i + 1)) && (i += 1, segment += string[i]), (curByteLength += getByteLength(segment)) === byteLength) return string.slice(0, i + 1); - if (curByteLength > byteLength) return string.slice(0, i - segment.length + 1) + if (typeof string !== "string") { + throw new Error("Input must be string"); } - return string + + var charLength = string.length; + var curByteLength = 0; + var codePoint; + var segment; + + for (var i = 0; i < charLength; i += 1) { + codePoint = string.charCodeAt(i); + segment = string[i]; + + if (isHighSurrogate(codePoint) && isLowSurrogate(string.charCodeAt(i + 1))) { + i += 1; + segment += string[i]; + } + + curByteLength += getByteLength(segment); + + if (curByteLength === byteLength) { + return string.slice(0, i + 1); + } + else if (curByteLength > byteLength) { + return string.slice(0, i - segment.length + 1); + } + } + + return string; } - var illegalRe = /[\/\?<>\\:\*\|":]/g, - controlRe = /[\x00-\x1f\x80-\x9f]/g, - reservedRe = /^\.+$/, - windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i, - windowsTrailingRe = /[\. ]+$/; + return { - sanitize: function(input, replacement) { - return truncate(input.replace(illegalRe, replacement).replace(controlRe, replacement).replace(reservedRe, replacement).replace(windowsReservedRe, replacement).replace(windowsTrailingRe, replacement), 255) + sanitize: function (input, replacement) { + var sanitized = input + .replace(illegalRe, replacement) + .replace(controlRe, replacement) + .replace(reservedRe, replacement) + .replace(windowsReservedRe, replacement) + .replace(windowsTrailingRe, replacement); + return truncate(sanitized, 255); } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/scroller/smoothscroller.js b/src/bower_components/emby-webcomponents/scroller/smoothscroller.js index dabd776911..cfa1e07a00 100644 --- a/src/bower_components/emby-webcomponents/scroller/smoothscroller.js +++ b/src/bower_components/emby-webcomponents/scroller/smoothscroller.js @@ -1,292 +1,937 @@ -define(["browser", "layoutManager", "dom", "focusManager", "ResizeObserver", "scrollStyles"], function(browser, layoutManager, dom, focusManager, ResizeObserver) { - "use strict"; +define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'scrollStyles'], function (browser, layoutManager, dom, focusManager, ResizeObserver) { + 'use strict'; + /** +* Return type of the value. +* +* @param {Mixed} value +* +* @return {String} +*/ function type(value) { - return null == value ? String(value) : "object" == typeof value || "function" == typeof value ? Object.prototype.toString.call(value).match(/\s([a-z]+)/i)[1].toLowerCase() || "object" : typeof value - } - - function disableOneEvent(event) { - event.preventDefault(), event.stopPropagation(), this.removeEventListener(event.type, disableOneEvent) - } - - function within(number, min, max) { - return number < min ? min : number > max ? max : number - } - var dragMouseEvents = ["mousemove", "mouseup"], - dragTouchEvents = ["touchmove", "touchend"], - wheelEvent = document.implementation.hasFeature("Event.wheel", "3.0") ? "wheel" : "mousewheel", - interactiveElements = ["INPUT", "SELECT", "TEXTAREA"], - abs = Math.abs, - sqrt = Math.sqrt, - pow = Math.pow, - round = Math.round, - max = Math.max, - scrollerFactory = (Math.min, function(frame, options) { - function ensureSizeInfo() { - requiresReflow && (requiresReflow = !1, frameSize = o.horizontal ? frame.offsetWidth : frame.offsetHeight, slideeSize = o.scrollWidth || Math.max(slideeElement[o.horizontal ? "offsetWidth" : "offsetHeight"], slideeElement[o.horizontal ? "scrollWidth" : "scrollHeight"]), self._pos.end = max(slideeSize - frameSize, 0)) - } - - function load(isInit) { - if (requiresReflow = !0, !isInit) { - ensureSizeInfo(); - var pos = self._pos; - self.slideTo(within(pos.dest, pos.start, pos.end)) - } - } - - function initFrameResizeObserver() { - var observerOptions = {}; - self.frameResizeObserver = new ResizeObserver(onResize, observerOptions), self.frameResizeObserver.observe(frame) - } - - function nativeScrollTo(container, pos, immediate) { - container.scroll ? o.horizontal ? container.scroll({ - left: pos, - behavior: immediate ? "instant" : "smooth" - }) : container.scroll({ - top: pos, - behavior: immediate ? "instant" : "smooth" - }) : !immediate && container.scrollTo ? o.horizontal ? container.scrollTo(Math.round(pos), 0) : container.scrollTo(0, Math.round(pos)) : o.horizontal ? container.scrollLeft = Math.round(pos) : container.scrollTop = Math.round(pos) - } - - function setStyleProperty(elem, name, value, speed, resetTransition) { - var style = elem.style; - (resetTransition || browser.edge) && (style.transition = "none", elem.offsetWidth), style.transition = "transform " + speed + "ms ease-out", style[name] = value - } - - function dispatchScrollEventIfNeeded() { - o.dispatchScrollEvent && frame.dispatchEvent(new CustomEvent(self.getScrollEventName(), { - bubbles: !0, - cancelable: !1 - })) - } - - function renderAnimateWithTransform(fromPosition, toPosition, immediate) { - var speed = o.speed; - immediate && (speed = o.immediateSpeed || 50), o.horizontal ? setStyleProperty(slideeElement, "transform", "translateX(" + -round(toPosition) + "px)", speed) : setStyleProperty(slideeElement, "transform", "translateY(" + -round(toPosition) + "px)", speed), self._pos.cur = toPosition, dispatchScrollEventIfNeeded() - } - - function getBoundingClientRect(elem) { - return elem.getBoundingClientRect ? elem.getBoundingClientRect() : { - top: 0, - left: 0 - } - } - - function dragInitSlidee(event) { - var isTouch = "touchstart" === event.type; - if (!(dragging.init || !isTouch && isInteractive(event.target)) && (isTouch ? o.touchDragging : o.mouseDragging && event.which < 2)) { - isTouch || event.preventDefault(), dragging.released = 0, dragging.init = 0, dragging.source = event.target, dragging.touch = isTouch; - var pointer = isTouch ? event.touches[0] : event; - dragging.initX = pointer.pageX, dragging.initY = pointer.pageY, dragging.initPos = self._pos.cur, dragging.start = +new Date, dragging.time = 0, dragging.path = 0, dragging.delta = 0, dragging.locked = 0, dragging.pathToLock = isTouch ? 30 : 10, transform && (isTouch ? dragTouchEvents.forEach(function(eventName) { - dom.addEventListener(document, eventName, dragHandler, { - passive: !0 - }) - }) : dragMouseEvents.forEach(function(eventName) { - dom.addEventListener(document, eventName, dragHandler, { - passive: !0 - }) - })) - } - } - - function dragHandler(event) { - dragging.released = "mouseup" === event.type || "touchend" === event.type; - var pointer = dragging.touch ? event[dragging.released ? "changedTouches" : "touches"][0] : event; - if (dragging.pathX = pointer.pageX - dragging.initX, dragging.pathY = pointer.pageY - dragging.initY, dragging.path = sqrt(pow(dragging.pathX, 2) + pow(dragging.pathY, 2)), dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY, dragging.released || !(dragging.path < 1)) { - if (!dragging.init) { - if (dragging.path < o.dragThreshold) return dragging.released ? dragEnd() : void 0; - if (!(o.horizontal ? abs(dragging.pathX) > abs(dragging.pathY) : abs(dragging.pathX) < abs(dragging.pathY))) return dragEnd(); - dragging.init = 1 - }!dragging.locked && dragging.path > dragging.pathToLock && (dragging.locked = 1, dragging.source.addEventListener("click", disableOneEvent)), dragging.released && dragEnd(), self.slideTo(round(dragging.initPos - dragging.delta)) - } - } - - function dragEnd() { - dragging.released = !0, dragTouchEvents.forEach(function(eventName) { - dom.removeEventListener(document, eventName, dragHandler, { - passive: !0 - }) - }), dragMouseEvents.forEach(function(eventName) { - dom.removeEventListener(document, eventName, dragHandler, { - passive: !0 - }) - }), setTimeout(function() { - dragging.source.removeEventListener("click", disableOneEvent) - }), dragging.init = 0 - } - - function isInteractive(element) { - for (; element;) { - if (-1 !== interactiveElements.indexOf(element.tagName)) return !0; - element = element.parentNode - } - return !1 - } - - function normalizeWheelDelta(event) { - return scrolling.curDelta = (o.horizontal ? event.deltaY || event.deltaX : event.deltaY) || -event.wheelDelta, transform && (scrolling.curDelta /= 1 === event.deltaMode ? 3 : 100), scrolling.curDelta - } - - function scrollHandler(event) { - ensureSizeInfo(); - var pos = self._pos; - if (o.scrollBy && pos.start !== pos.end) { - var delta = normalizeWheelDelta(event); - transform ? (delta > 0 && pos.dest < pos.end || delta < 0 && (pos.dest, pos.start), self.slideBy(o.scrollBy * delta)) : (isSmoothScrollSupported && (delta *= 12), o.horizontal ? nativeScrollElement.scrollLeft += delta : nativeScrollElement.scrollTop += delta) - } - } - - function onResize(entries) { - var entry = entries[0]; - if (entry) { - var newRect = entry.contentRect; - if (0 === newRect.width || 0 === newRect.height) return; - newRect.width === contentRect.width && newRect.height === contentRect.height || (contentRect = newRect, load(!1)) - } - } - - function resetScroll() { - o.horizontal ? this.scrollLeft = 0 : this.scrollTop = 0 - } - - function onFrameClick(e) { - if (1 === e.which) { - var focusableParent = focusManager.focusableParent(e.target); - focusableParent && focusableParent !== document.activeElement && focusableParent.focus() - } - } - var o = Object.assign({}, { - slidee: null, - horizontal: !1, - mouseWheel: !0, - scrollBy: 0, - dragSource: null, - mouseDragging: 1, - touchDragging: 1, - dragThreshold: 3, - intervactive: null, - speed: 0 - }, options), - isSmoothScrollSupported = "scrollBehavior" in document.documentElement.style; - !1 === options.allowNativeScroll ? options.enableNativeScroll = !1 : isSmoothScrollSupported && (browser.firefox && !layoutManager.tv || options.allowNativeSmoothScroll) ? options.enableNativeScroll = !0 : options.requireAnimation && (browser.animate || browser.supportsCssAnimation()) ? options.enableNativeScroll = !1 : layoutManager.tv && browser.animate || (options.enableNativeScroll = !0), browser.web0s && (options.enableNativeScroll = !0); - var self = this; - self.options = o; - var slideeElement = o.slidee ? o.slidee : function(n, elem) { - for (var matched = []; n; n = n.nextSibling) 1 === n.nodeType && n !== elem && matched.push(n); - return matched - }(frame.firstChild)[0]; - self._pos = { - start: 0, - center: 0, - end: 0, - cur: 0, - dest: 0 - }; - var transform = !options.enableNativeScroll, - scrollSource = frame, - dragSourceElement = o.dragSource ? o.dragSource : frame, - dragging = { - released: 1 - }, - scrolling = { - last: 0, - delta: 0, - resetTime: 200 - }; - self.initialized = 0, self.slidee = slideeElement, self.options = o, self.dragging = dragging; - var nativeScrollElement = frame, - requiresReflow = !0, - frameSize = 0, - slideeSize = 0; - self.reload = function() { - load() - }, self.getScrollEventName = function() { - return transform ? "scrollanimate" : "scroll" - }, self.getScrollSlider = function() { - return slideeElement - }, self.getScrollFrame = function() { - return frame - }; - var lastAnimate; - self.slideTo = function(newPos, immediate, fullItemPos) { - ensureSizeInfo(); - var pos = self._pos; - if (newPos = within(newPos, pos.start, pos.end), !transform) return void nativeScrollTo(nativeScrollElement, newPos, immediate); - var from = pos.cur; - immediate = immediate || dragging.init || !o.speed; - var now = (new Date).getTime(); - o.autoImmediate && !immediate && now - (lastAnimate || 0) <= 50 && (immediate = !0), !immediate && o.skipSlideToWhenVisible && fullItemPos && fullItemPos.isVisible || newPos !== pos.dest && (pos.dest = newPos, renderAnimateWithTransform(from, newPos, immediate), lastAnimate = now) - }, self.getPos = function(item) { - var scrollElement = transform ? slideeElement : nativeScrollElement, - slideeOffset = getBoundingClientRect(scrollElement), - itemOffset = getBoundingClientRect(item), - offset = (o.horizontal ? slideeOffset.left : slideeOffset.top, o.horizontal ? slideeOffset.right : slideeOffset.bottom, o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top), - size = o.horizontal ? itemOffset.width : itemOffset.height; - size || 0 === size || (size = item[o.horizontal ? "offsetWidth" : "offsetHeight"]); - var centerOffset = o.centerOffset || 0; - transform || (centerOffset = 0, o.horizontal ? offset += nativeScrollElement.scrollLeft : offset += nativeScrollElement.scrollTop), ensureSizeInfo(); - var currentStart = self._pos.cur, - currentEnd = currentStart + frameSize; - return { - start: offset, - center: offset + centerOffset - frameSize / 2 + size / 2, - end: offset - frameSize + size, - size: size, - isVisible: offset >= currentStart && offset + size <= currentEnd - } - }, self.getCenterPosition = function(item) { - ensureSizeInfo(); - var pos = self.getPos(item); - return within(pos.center, pos.start, pos.end) - }, self.destroy = function() { - return self.frameResizeObserver && (self.frameResizeObserver.disconnect(), self.frameResizeObserver = null), dom.removeEventListener(frame, "scroll", resetScroll, { - passive: !0 - }), dom.removeEventListener(scrollSource, wheelEvent, scrollHandler, { - passive: !0 - }), dom.removeEventListener(dragSourceElement, "touchstart", dragInitSlidee, { - passive: !0 - }), dom.removeEventListener(frame, "click", onFrameClick, { - passive: !0, - capture: !0 - }), dom.removeEventListener(dragSourceElement, "mousedown", dragInitSlidee, {}), self.initialized = 0, self - }; - var contentRect = {}; - self.getScrollPosition = function() { - return transform ? self._pos.cur : o.horizontal ? nativeScrollElement.scrollLeft : nativeScrollElement.scrollTop - }, self.getScrollSize = function() { - return transform ? slideeSize : o.horizontal ? nativeScrollElement.scrollWidth : nativeScrollElement.scrollHeight - }, self.init = function() { - if (!self.initialized) return transform ? (frame.style.overflow = "hidden", slideeElement.style["will-change"] = "transform", slideeElement.style.transition = "transform " + o.speed + "ms ease-out", o.horizontal ? slideeElement.classList.add("animatedScrollX") : slideeElement.classList.add("animatedScrollY")) : o.horizontal ? (layoutManager.desktop && !o.hideScrollbar ? nativeScrollElement.classList.add("scrollX") : (nativeScrollElement.classList.add("scrollX"), nativeScrollElement.classList.add("hiddenScrollX"), layoutManager.tv && !1 !== o.allowNativeSmoothScroll && nativeScrollElement.classList.add("smoothScrollX")), o.forceHideScrollbars && nativeScrollElement.classList.add("hiddenScrollX-forced")) : (layoutManager.desktop && !o.hideScrollbar ? nativeScrollElement.classList.add("scrollY") : (nativeScrollElement.classList.add("scrollY"), nativeScrollElement.classList.add("hiddenScrollY"), layoutManager.tv && !1 !== o.allowNativeSmoothScroll && nativeScrollElement.classList.add("smoothScrollY")), o.forceHideScrollbars && nativeScrollElement.classList.add("hiddenScrollY-forced")), (transform || layoutManager.tv) && dom.addEventListener(dragSourceElement, "mousedown", dragInitSlidee, {}), initFrameResizeObserver(), transform ? (dom.addEventListener(dragSourceElement, "touchstart", dragInitSlidee, { - passive: !0 - }), o.horizontal || dom.addEventListener(frame, "scroll", resetScroll, { - passive: !0 - }), o.mouseWheel && dom.addEventListener(scrollSource, wheelEvent, scrollHandler, { - passive: !0 - })) : o.horizontal && o.mouseWheel && dom.addEventListener(scrollSource, wheelEvent, scrollHandler, { - passive: !0 - }), dom.addEventListener(frame, "click", onFrameClick, { - passive: !0, - capture: !0 - }), self.initialized = 1, load(!0), self - } - }); - return scrollerFactory.prototype.slideBy = function(delta, immediate) { - delta && this.slideTo(this._pos.dest + delta, immediate) - }, scrollerFactory.prototype.to = function(location, item, immediate) { - if ("boolean" === type(item) && (immediate = item, item = void 0), void 0 === item) this.slideTo(this._pos[location], immediate); - else { - var itemPos = this.getPos(item); - itemPos && this.slideTo(itemPos[location], immediate, itemPos) + if (value == null) { + return String(value); } - }, scrollerFactory.prototype.toStart = function(item, immediate) { - this.to("start", item, immediate) - }, scrollerFactory.prototype.toEnd = function(item, immediate) { - this.to("end", item, immediate) - }, scrollerFactory.prototype.toCenter = function(item, immediate) { - this.to("center", item, immediate) - }, scrollerFactory.create = function(frame, options) { + + if (typeof value === 'object' || typeof value === 'function') { + return Object.prototype.toString.call(value).match(/\s([a-z]+)/i)[1].toLowerCase() || 'object'; + } + + return typeof value; + } + + /** + * Disables an event it was triggered on and unbinds itself. + * + * @param {Event} event + * + * @return {Void} + */ + function disableOneEvent(event) { + /*jshint validthis:true */ + event.preventDefault(); + event.stopPropagation(); + this.removeEventListener(event.type, disableOneEvent); + } + + /** + * Make sure that number is within the limits. + * + * @param {Number} number + * @param {Number} min + * @param {Number} max + * + * @return {Number} + */ + function within(number, min, max) { + return number < min ? min : number > max ? max : number; + } + + // Other global values + var dragMouseEvents = ['mousemove', 'mouseup']; + var dragTouchEvents = ['touchmove', 'touchend']; + var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel'); + var interactiveElements = ['INPUT', 'SELECT', 'TEXTAREA']; + var tmpArray = []; + var time; + + // Math shorthands + var abs = Math.abs; + var sqrt = Math.sqrt; + var pow = Math.pow; + var round = Math.round; + var max = Math.max; + var min = Math.min; + + var scrollerFactory = function (frame, options) { + + // Extend options + var o = Object.assign({}, { + slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE. + horizontal: false, // Switch to horizontal mode. + + // Scrolling + mouseWheel: true, + scrollBy: 0, // Pixels or items to move per one mouse scroll. 0 to disable scrolling + + // Dragging + dragSource: null, // Selector or DOM element for catching dragging events. Default is FRAME. + mouseDragging: 1, // Enable navigation by dragging the SLIDEE with mouse cursor. + touchDragging: 1, // Enable navigation by dragging the SLIDEE with touch events. + dragThreshold: 3, // Distance in pixels before Sly recognizes dragging. + intervactive: null, // Selector for special interactive elements. + + // Mixed options + speed: 0, // Animations speed in milliseconds. 0 to disable animations. + + }, options); + + var isSmoothScrollSupported = 'scrollBehavior' in document.documentElement.style; + + // native scroll is a must with touch input + // also use native scroll when scrolling vertically in desktop mode - excluding horizontal because the mouse wheel support is choppy at the moment + // in cases with firefox, if the smooth scroll api is supported then use that because their implementation is very good + if (options.allowNativeScroll === false) { + options.enableNativeScroll = false; + } + else if (isSmoothScrollSupported && ((browser.firefox && !layoutManager.tv) || options.allowNativeSmoothScroll)) { + // native smooth scroll + options.enableNativeScroll = true; + } + else if (options.requireAnimation && (browser.animate || browser.supportsCssAnimation())) { + + // transform is the only way to guarantee animation + options.enableNativeScroll = false; + } + else if (!layoutManager.tv || !browser.animate) { + + options.enableNativeScroll = true; + } + + // Need this for the magic wheel. With the animated scroll the magic wheel will run off of the screen + if (browser.web0s) { + options.enableNativeScroll = true; + } + + // Private variables + var self = this; + self.options = o; + + // Frame + var slideeElement = o.slidee ? o.slidee : sibling(frame.firstChild)[0]; + self._pos = { + start: 0, + center: 0, + end: 0, + cur: 0, + dest: 0 + }; + + var transform = !options.enableNativeScroll; + + // Miscellaneous + var scrollSource = frame; + var dragSourceElement = o.dragSource ? o.dragSource : frame; + var dragging = { + released: 1 + }; + var scrolling = { + last: 0, + delta: 0, + resetTime: 200 + }; + + // Expose properties + self.initialized = 0; + self.slidee = slideeElement; + self.options = o; + self.dragging = dragging; + + var nativeScrollElement = frame; + + function sibling(n, elem) { + var matched = []; + + for (; n; n = n.nextSibling) { + if (n.nodeType === 1 && n !== elem) { + matched.push(n); + } + } + return matched; + } + + var requiresReflow = true; + + var frameSize = 0; + var slideeSize = 0; + function ensureSizeInfo() { + + if (requiresReflow) { + + requiresReflow = false; + + // Reset global variables + frameSize = o.horizontal ? (frame).offsetWidth : (frame).offsetHeight; + + slideeSize = o.scrollWidth || Math.max(slideeElement[o.horizontal ? 'offsetWidth' : 'offsetHeight'], slideeElement[o.horizontal ? 'scrollWidth' : 'scrollHeight']); + + // Set position limits & relativess + self._pos.end = max(slideeSize - frameSize, 0); + } + } + + /** + * Loading function. + * + * Populate arrays, set sizes, bind events, ... + * + * @param {Boolean} [isInit] Whether load is called from within self.init(). + * @return {Void} + */ + function load(isInit) { + + requiresReflow = true; + + if (!isInit) { + + ensureSizeInfo(); + + // Fix possible overflowing + var pos = self._pos; + self.slideTo(within(pos.dest, pos.start, pos.end)); + } + } + + function initFrameResizeObserver() { + + var observerOptions = {}; + + self.frameResizeObserver = new ResizeObserver(onResize, observerOptions); + + self.frameResizeObserver.observe(frame); + } + + self.reload = function () { load(); }; + + self.getScrollEventName = function () { + return transform ? 'scrollanimate' : 'scroll'; + }; + + self.getScrollSlider = function () { + return slideeElement; + }; + + self.getScrollFrame = function () { + return frame; + }; + + function nativeScrollTo(container, pos, immediate) { + + + if (container.scroll) { + if (o.horizontal) { + + container.scroll({ + left: pos, + behavior: immediate ? 'instant' : 'smooth' + }); + } else { + + container.scroll({ + top: pos, + behavior: immediate ? 'instant' : 'smooth' + }); + } + } + else if (!immediate && container.scrollTo) { + if (o.horizontal) { + container.scrollTo(Math.round(pos), 0); + } else { + container.scrollTo(0, Math.round(pos)); + } + } else { + if (o.horizontal) { + container.scrollLeft = Math.round(pos); + } else { + container.scrollTop = Math.round(pos); + } + } + } + + var lastAnimate; + + /** + * Animate to a position. + * + * @param {Int} newPos New position. + * @param {Bool} immediate Reposition immediately without an animation. + * + * @return {Void} + */ + self.slideTo = function (newPos, immediate, fullItemPos) { + + ensureSizeInfo(); + var pos = self._pos; + + newPos = within(newPos, pos.start, pos.end); + + if (!transform) { + + nativeScrollTo(nativeScrollElement, newPos, immediate); + return; + } + + // Update the animation object + var from = pos.cur; + immediate = immediate || dragging.init || !o.speed; + + var now = new Date().getTime(); + + if (o.autoImmediate) { + if (!immediate && (now - (lastAnimate || 0)) <= 50) { + immediate = true; + } + } + + if (!immediate && o.skipSlideToWhenVisible && fullItemPos && fullItemPos.isVisible) { + + return; + } + + // Start animation rendering + if (newPos !== pos.dest) { + pos.dest = newPos; + + renderAnimateWithTransform(from, newPos, immediate); + + lastAnimate = now; + } + }; + + function setStyleProperty(elem, name, value, speed, resetTransition) { + + var style = elem.style; + + if (resetTransition || browser.edge) { + style.transition = 'none'; + void elem.offsetWidth; + } + + style.transition = 'transform ' + speed + 'ms ease-out'; + style[name] = value; + } + + function dispatchScrollEventIfNeeded() { + if (o.dispatchScrollEvent) { + frame.dispatchEvent(new CustomEvent(self.getScrollEventName(), { + bubbles: true, + cancelable: false + })); + } + } + + function renderAnimateWithTransform(fromPosition, toPosition, immediate) { + + var speed = o.speed; + + if (immediate) { + speed = o.immediateSpeed || 50; + } + + if (o.horizontal) { + setStyleProperty(slideeElement, 'transform', 'translateX(' + (-round(toPosition)) + 'px)', speed); + } else { + setStyleProperty(slideeElement, 'transform', 'translateY(' + (-round(toPosition)) + 'px)', speed); + } + self._pos.cur = toPosition; + + dispatchScrollEventIfNeeded(); + } + + function getBoundingClientRect(elem) { + + // Support: BlackBerry 5, iOS 3 (original iPhone) + // If we don't have gBCR, just use 0,0 rather than error + if (elem.getBoundingClientRect) { + return elem.getBoundingClientRect(); + } else { + return { top: 0, left: 0 }; + } + } + + /** + * Returns the position object. + * + * @param {Mixed} item + * + * @return {Object} + */ + self.getPos = function (item) { + + var scrollElement = transform ? slideeElement : nativeScrollElement; + var slideeOffset = getBoundingClientRect(scrollElement); + var itemOffset = getBoundingClientRect(item); + + var slideeStartPos = o.horizontal ? slideeOffset.left : slideeOffset.top; + var slideeEndPos = o.horizontal ? slideeOffset.right : slideeOffset.bottom; + + var offset = o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top; + + var size = o.horizontal ? itemOffset.width : itemOffset.height; + if (!size && size !== 0) { + size = item[o.horizontal ? 'offsetWidth' : 'offsetHeight']; + } + + var centerOffset = o.centerOffset || 0; + + if (!transform) { + centerOffset = 0; + if (o.horizontal) { + offset += nativeScrollElement.scrollLeft; + } else { + offset += nativeScrollElement.scrollTop; + } + } + + ensureSizeInfo(); + + var currentStart = self._pos.cur; + var currentEnd = currentStart + frameSize; + + //console.log('offset:' + offset + ' currentStart:' + currentStart + ' currentEnd:' + currentEnd); + var isVisible = offset >= currentStart && (offset + size) <= currentEnd; + + return { + start: offset, + center: offset + centerOffset - (frameSize / 2) + (size / 2), + end: offset - frameSize + size, + size: size, + isVisible: isVisible + }; + }; + + self.getCenterPosition = function (item) { + + ensureSizeInfo(); + + var pos = self.getPos(item); + return within(pos.center, pos.start, pos.end); + }; + + function dragInitSlidee(event) { + var isTouch = event.type === 'touchstart'; + + // Ignore when already in progress, or interactive element in non-touch navivagion + if (dragging.init || !isTouch && isInteractive(event.target)) { + return; + } + + // SLIDEE dragging conditions + if (!(isTouch ? o.touchDragging : o.mouseDragging && event.which < 2)) { + return; + } + + if (!isTouch) { + // prevents native image dragging in Firefox + event.preventDefault(); + } + + // Reset dragging object + dragging.released = 0; + + // Properties used in dragHandler + dragging.init = 0; + dragging.source = event.target; + dragging.touch = isTouch; + var pointer = isTouch ? event.touches[0] : event; + dragging.initX = pointer.pageX; + dragging.initY = pointer.pageY; + dragging.initPos = self._pos.cur; + dragging.start = +new Date(); + dragging.time = 0; + dragging.path = 0; + dragging.delta = 0; + dragging.locked = 0; + dragging.pathToLock = isTouch ? 30 : 10; + + // Bind dragging events + if (transform) { + + if (isTouch) { + dragTouchEvents.forEach(function (eventName) { + dom.addEventListener(document, eventName, dragHandler, { + passive: true + }); + }); + } else { + dragMouseEvents.forEach(function (eventName) { + dom.addEventListener(document, eventName, dragHandler, { + passive: true + }); + }); + } + } + } + + /** + * Handler for dragging scrollbar handle or SLIDEE. + * + * @param {Event} event + * + * @return {Void} + */ + function dragHandler(event) { + dragging.released = event.type === 'mouseup' || event.type === 'touchend'; + var pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event; + dragging.pathX = pointer.pageX - dragging.initX; + dragging.pathY = pointer.pageY - dragging.initY; + dragging.path = sqrt(pow(dragging.pathX, 2) + pow(dragging.pathY, 2)); + dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY; + + if (!dragging.released && dragging.path < 1) { + return; + } + + // We haven't decided whether this is a drag or not... + if (!dragging.init) { + // If the drag path was very short, maybe it's not a drag? + if (dragging.path < o.dragThreshold) { + // If the pointer was released, the path will not become longer and it's + // definitely not a drag. If not released yet, decide on next iteration + return dragging.released ? dragEnd() : undefined; + } else { + // If dragging path is sufficiently long we can confidently start a drag + // if drag is in different direction than scroll, ignore it + if (o.horizontal ? abs(dragging.pathX) > abs(dragging.pathY) : abs(dragging.pathX) < abs(dragging.pathY)) { + dragging.init = 1; + } else { + return dragEnd(); + } + } + } + + //event.preventDefault(); + + // Disable click on a source element, as it is unwelcome when dragging + if (!dragging.locked && dragging.path > dragging.pathToLock) { + dragging.locked = 1; + dragging.source.addEventListener('click', disableOneEvent); + } + + // Cancel dragging on release + if (dragging.released) { + dragEnd(); + } + + self.slideTo(round(dragging.initPos - dragging.delta)); + } + + /** + * Stops dragging and cleans up after it. + * + * @return {Void} + */ + function dragEnd() { + dragging.released = true; + + dragTouchEvents.forEach(function (eventName) { + dom.removeEventListener(document, eventName, dragHandler, { + passive: true + }); + }); + + dragMouseEvents.forEach(function (eventName) { + dom.removeEventListener(document, eventName, dragHandler, { + passive: true + }); + }); + + // Make sure that disableOneEvent is not active in next tick. + setTimeout(function () { + dragging.source.removeEventListener('click', disableOneEvent); + }); + + dragging.init = 0; + } + + /** + * Check whether element is interactive. + * + * @return {Boolean} + */ + function isInteractive(element) { + + while (element) { + + if (interactiveElements.indexOf(element.tagName) !== -1) { + return true; + } + + element = element.parentNode; + } + return false; + } + + /** + * Mouse wheel delta normalization. + * + * @param {Event} event + * + * @return {Int} + */ + function normalizeWheelDelta(event) { + // wheelDelta needed only for IE8- + scrolling.curDelta = ((o.horizontal ? event.deltaY || event.deltaX : event.deltaY) || -event.wheelDelta); + + if (transform) { + scrolling.curDelta /= event.deltaMode === 1 ? 3 : 100; + } + return scrolling.curDelta; + } + + /** + * Mouse scrolling handler. + * + * @param {Event} event + * + * @return {Void} + */ + function scrollHandler(event) { + + ensureSizeInfo(); + var pos = self._pos; + // Ignore if there is no scrolling to be done + if (!o.scrollBy || pos.start === pos.end) { + return; + } + var delta = normalizeWheelDelta(event); + + if (transform) { + // Trap scrolling only when necessary and/or requested + if (delta > 0 && pos.dest < pos.end || delta < 0 && pos.dest > pos.start) { + //stopDefault(event, 1); + } + + self.slideBy(o.scrollBy * delta); + } else { + + if (isSmoothScrollSupported) { + delta *= 12; + } + + if (o.horizontal) { + nativeScrollElement.scrollLeft += delta; + } else { + nativeScrollElement.scrollTop += delta; + } + } + } + + /** + * Destroys instance and everything it created. + * + * @return {Void} + */ + self.destroy = function () { + + if (self.frameResizeObserver) { + self.frameResizeObserver.disconnect(); + self.frameResizeObserver = null; + } + + // Reset native FRAME element scroll + dom.removeEventListener(frame, 'scroll', resetScroll, { + passive: true + }); + + dom.removeEventListener(scrollSource, wheelEvent, scrollHandler, { + passive: true + }); + + dom.removeEventListener(dragSourceElement, 'touchstart', dragInitSlidee, { + passive: true + }); + + dom.removeEventListener(frame, 'click', onFrameClick, { + passive: true, + capture: true + }); + + dom.removeEventListener(dragSourceElement, 'mousedown', dragInitSlidee, { + //passive: true + }); + + // Reset initialized status and return the instance + self.initialized = 0; + return self; + }; + + var contentRect = {}; + + function onResize(entries) { + + var entry = entries[0]; + + if (entry) { + + var newRect = entry.contentRect; + + // handle element being hidden + if (newRect.width === 0 || newRect.height === 0) { + return; + } + + if (newRect.width !== contentRect.width || newRect.height !== contentRect.height) { + + contentRect = newRect; + + load(false); + } + } + } + + function resetScroll() { + if (o.horizontal) { + this.scrollLeft = 0; + } else { + this.scrollTop = 0; + } + } + + function onFrameClick(e) { + if (e.which === 1) { + var focusableParent = focusManager.focusableParent(e.target); + if (focusableParent && focusableParent !== document.activeElement) { + focusableParent.focus(); + } + } + } + + self.getScrollPosition = function () { + + if (transform) { + return self._pos.cur; + } + + if (o.horizontal) { + return nativeScrollElement.scrollLeft; + } else { + return nativeScrollElement.scrollTop; + } + }; + + self.getScrollSize = function () { + + if (transform) { + return slideeSize; + } + + if (o.horizontal) { + return nativeScrollElement.scrollWidth; + } else { + return nativeScrollElement.scrollHeight; + } + }; + + /** + * Initialize. + * + * @return {Object} + */ + self.init = function () { + if (self.initialized) { + return; + } + + if (!transform) { + if (o.horizontal) { + if (layoutManager.desktop && !o.hideScrollbar) { + nativeScrollElement.classList.add('scrollX'); + } else { + nativeScrollElement.classList.add('scrollX'); + nativeScrollElement.classList.add('hiddenScrollX'); + + if (layoutManager.tv && o.allowNativeSmoothScroll !== false) { + nativeScrollElement.classList.add('smoothScrollX'); + } + } + + if (o.forceHideScrollbars) { + nativeScrollElement.classList.add('hiddenScrollX-forced'); + } + } else { + if (layoutManager.desktop && !o.hideScrollbar) { + nativeScrollElement.classList.add('scrollY'); + } else { + nativeScrollElement.classList.add('scrollY'); + nativeScrollElement.classList.add('hiddenScrollY'); + + if (layoutManager.tv && o.allowNativeSmoothScroll !== false) { + nativeScrollElement.classList.add('smoothScrollY'); + } + } + + if (o.forceHideScrollbars) { + nativeScrollElement.classList.add('hiddenScrollY-forced'); + } + } + } else { + frame.style.overflow = 'hidden'; + slideeElement.style['will-change'] = 'transform'; + slideeElement.style.transition = 'transform ' + o.speed + 'ms ease-out'; + + if (o.horizontal) { + slideeElement.classList.add('animatedScrollX'); + } else { + slideeElement.classList.add('animatedScrollY'); + } + } + + if (transform || layoutManager.tv) { + // This can prevent others from being able to listen to mouse events + dom.addEventListener(dragSourceElement, 'mousedown', dragInitSlidee, { + //passive: true + }); + } + + initFrameResizeObserver(); + + if (transform) { + + dom.addEventListener(dragSourceElement, 'touchstart', dragInitSlidee, { + passive: true + }); + + if (!o.horizontal) { + dom.addEventListener(frame, 'scroll', resetScroll, { + passive: true + }); + } + + if (o.mouseWheel) { + // Scrolling navigation + dom.addEventListener(scrollSource, wheelEvent, scrollHandler, { + passive: true + }); + } + + } else if (o.horizontal) { + + // Don't bind to mouse events with vertical scroll since the mouse wheel can handle this natively + + if (o.mouseWheel) { + // Scrolling navigation + dom.addEventListener(scrollSource, wheelEvent, scrollHandler, { + passive: true + }); + } + } + + dom.addEventListener(frame, 'click', onFrameClick, { + passive: true, + capture: true + }); + + // Mark instance as initialized + self.initialized = 1; + + // Load + load(true); + + // Return instance + return self; + }; + }; + + /** + * Slide SLIDEE by amount of pixels. + * + * @param {Int} delta Pixels/Items. Positive means forward, negative means backward. + * @param {Bool} immediate Reposition immediately without an animation. + * + * @return {Void} + */ + scrollerFactory.prototype.slideBy = function (delta, immediate) { + if (!delta) { + return; + } + this.slideTo(this._pos.dest + delta, immediate); + }; + + /** + * Core method for handling `toLocation` methods. + * + * @param {String} location + * @param {Mixed} item + * @param {Bool} immediate + * + * @return {Void} + */ + scrollerFactory.prototype.to = function (location, item, immediate) { + // Optional arguments logic + if (type(item) === 'boolean') { + immediate = item; + item = undefined; + } + + if (item === undefined) { + this.slideTo(this._pos[location], immediate); + } else { + + //if (!transform) { + + // item.scrollIntoView(); + // return; + //} + + var itemPos = this.getPos(item); + + if (itemPos) { + this.slideTo(itemPos[location], immediate, itemPos); + } + } + }; + + /** + * Animate element or the whole SLIDEE to the start of the frame. + * + * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE. + * @param {Bool} immediate Reposition immediately without an animation. + * + * @return {Void} + */ + scrollerFactory.prototype.toStart = function (item, immediate) { + this.to('start', item, immediate); + }; + + /** + * Animate element or the whole SLIDEE to the end of the frame. + * + * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE. + * @param {Bool} immediate Reposition immediately without an animation. + * + * @return {Void} + */ + scrollerFactory.prototype.toEnd = function (item, immediate) { + this.to('end', item, immediate); + }; + + /** + * Animate element or the whole SLIDEE to the center of the frame. + * + * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE. + * @param {Bool} immediate Reposition immediately without an animation. + * + * @return {Void} + */ + scrollerFactory.prototype.toCenter = function (item, immediate) { + this.to('center', item, immediate); + }; + + scrollerFactory.create = function (frame, options) { var instance = new scrollerFactory(frame, options); - return Promise.resolve(instance) - }, scrollerFactory + return Promise.resolve(instance); + }; + + return scrollerFactory; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/scrollhelper.js b/src/bower_components/emby-webcomponents/scrollhelper.js index 4ae5262ec4..6280dc5062 100644 --- a/src/bower_components/emby-webcomponents/scrollhelper.js +++ b/src/bower_components/emby-webcomponents/scrollhelper.js @@ -1,77 +1,137 @@ -define(["focusManager", "dom", "scrollStyles"], function(focusManager, dom) { - "use strict"; +define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) { + 'use strict'; function getBoundingClientRect(elem) { - return elem.getBoundingClientRect ? elem.getBoundingClientRect() : { - top: 0, - left: 0 + + // Support: BlackBerry 5, iOS 3 (original iPhone) + // If we don't have gBCR, just use 0,0 rather than error + if (elem.getBoundingClientRect) { + return elem.getBoundingClientRect(); + } else { + return { top: 0, left: 0 }; } } function getPosition(scrollContainer, item, horizontal) { - var slideeOffset = getBoundingClientRect(scrollContainer), - itemOffset = getBoundingClientRect(item), - offset = horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top, - size = horizontal ? itemOffset.width : itemOffset.height; - size || 0 === size || (size = item[horizontal ? "offsetWidth" : "offsetHeight"]); + + var slideeOffset = getBoundingClientRect(scrollContainer); + var itemOffset = getBoundingClientRect(item); + + var offset = horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top; + var size = horizontal ? itemOffset.width : itemOffset.height; + if (!size && size !== 0) { + size = item[horizontal ? 'offsetWidth' : 'offsetHeight']; + } + var currentStart = horizontal ? scrollContainer.scrollLeft : scrollContainer.scrollTop; + offset += currentStart; - var frameSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight, - currentEnd = currentStart + frameSize; + + var frameSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight; + + var currentEnd = currentStart + frameSize; + + var isVisible = offset >= currentStart && (offset + size) <= currentEnd; + return { start: offset, - center: offset - frameSize / 2 + size / 2, + center: (offset - (frameSize / 2) + (size / 2)), end: offset - frameSize + size, size: size, - isVisible: offset >= currentStart && offset + size <= currentEnd - } + isVisible: isVisible + }; } function toCenter(container, elem, horizontal, skipWhenVisible) { var pos = getPosition(container, elem, horizontal); - skipWhenVisible && pos.isVisible || (container.scrollTo ? horizontal ? container.scrollTo(pos.center, 0) : container.scrollTo(0, pos.center) : horizontal ? container.scrollLeft = Math.round(pos.center) : container.scrollTop = Math.round(pos.center)) + + if (skipWhenVisible && pos.isVisible) { + return; + } + + if (container.scrollTo) { + if (horizontal) { + container.scrollTo(pos.center, 0); + } else { + container.scrollTo(0, pos.center); + } + } else { + if (horizontal) { + container.scrollLeft = Math.round(pos.center); + } else { + container.scrollTop = Math.round(pos.center); + } + } } function toStart(container, elem, horizontal, skipWhenVisible) { var pos = getPosition(container, elem, horizontal); - skipWhenVisible && pos.isVisible || (container.scrollTo ? horizontal ? container.scrollTo(pos.start, 0) : container.scrollTo(0, pos.start) : horizontal ? container.scrollLeft = Math.round(pos.start) : container.scrollTop = Math.round(pos.start)) + + if (skipWhenVisible && pos.isVisible) { + return; + } + + if (container.scrollTo) { + if (horizontal) { + container.scrollTo(pos.start, 0); + } else { + container.scrollTo(0, pos.start); + } + } else { + if (horizontal) { + container.scrollLeft = Math.round(pos.start); + } else { + container.scrollTop = Math.round(pos.start); + } + } } function centerOnFocus(e, scrollSlider, horizontal) { var focused = focusManager.focusableParent(e.target); - focused && toCenter(scrollSlider, focused, horizontal) + + if (focused) { + toCenter(scrollSlider, focused, horizontal); + } } function centerOnFocusHorizontal(e) { - centerOnFocus(e, this, !0) + centerOnFocus(e, this, true); + } + function centerOnFocusVertical(e) { + centerOnFocus(e, this, false); } - function centerOnFocusVertical(e) { - centerOnFocus(e, this, !1) - } return { getPosition: getPosition, centerFocus: { - on: function(element, horizontal) { - horizontal ? dom.addEventListener(element, "focus", centerOnFocusHorizontal, { - capture: !0, - passive: !0 - }) : dom.addEventListener(element, "focus", centerOnFocusVertical, { - capture: !0, - passive: !0 - }) + on: function (element, horizontal) { + if (horizontal) { + dom.addEventListener(element, 'focus', centerOnFocusHorizontal, { + capture: true, + passive: true + }); + } else { + dom.addEventListener(element, 'focus', centerOnFocusVertical, { + capture: true, + passive: true + }); + } }, - off: function(element, horizontal) { - horizontal ? dom.removeEventListener(element, "focus", centerOnFocusHorizontal, { - capture: !0, - passive: !0 - }) : dom.removeEventListener(element, "focus", centerOnFocusVertical, { - capture: !0, - passive: !0 - }) + off: function (element, horizontal) { + if (horizontal) { + dom.removeEventListener(element, 'focus', centerOnFocusHorizontal, { + capture: true, + passive: true + }); + } else { + dom.removeEventListener(element, 'focus', centerOnFocusVertical, { + capture: true, + passive: true + }); + } } }, toCenter: toCenter, toStart: toStart - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/scrollstyles.css b/src/bower_components/emby-webcomponents/scrollstyles.css index 7664b396c8..aa2f7dafad 100644 --- a/src/bower_components/emby-webcomponents/scrollstyles.css +++ b/src/bower_components/emby-webcomponents/scrollstyles.css @@ -1,49 +1,53 @@ -.smoothScrollX, -.smoothScrollY { - scroll-behavior: smooth -} - .scrollX { overflow-x: auto; -webkit-overflow-scrolling: touch; overflow-y: hidden; - white-space: nowrap + white-space: nowrap; } -.hiddenScrollX, -.layout-tv .scrollX { - -ms-overflow-style: none +.smoothScrollX { + scroll-behavior: smooth; +} + +.hiddenScrollX, .layout-tv .scrollX { + -ms-overflow-style: none; + /* Can't do this because it not only hides the scrollbar, but also prevents scrolling */ + /*overflow: -moz-scrollbars-none;*/ } .hiddenScrollX-forced { - overflow: -moz-scrollbars-none + overflow: -moz-scrollbars-none; +} + +.hiddenScrollX::-webkit-scrollbar, .layout-tv .scrollX::-webkit-scrollbar { + height: 0 !important; + display: none; +} + +.scrollY { + overflow-y: auto; + -webkit-overflow-scrolling: touch; + overflow-x: hidden; } -.scrollY, .smoothScrollY { overflow-y: auto; -webkit-overflow-scrolling: touch; - overflow-x: hidden + overflow-x: hidden; + scroll-behavior: smooth; } -.hiddenScrollX::-webkit-scrollbar, -.layout-tv .scrollX::-webkit-scrollbar { - height: 0 !important; - display: none -} - -.hiddenScrollY, -.layout-tv .smoothScrollY { - -ms-overflow-style: none +.hiddenScrollY, .layout-tv .smoothScrollY { + -ms-overflow-style: none; + /* Can't do this because it not only hides the scrollbar, but also prevents scrolling */ + /*overflow: -moz-scrollbars-none;*/ } .hiddenScrollY-forced { - overflow: -moz-scrollbars-none + overflow: -moz-scrollbars-none; } -.hiddenScrollY::-webkit-scrollbar, -.layout-tv .scrollY::-webkit-scrollbar, -.layout-tv .smoothScrollY::-webkit-scrollbar { +.hiddenScrollY::-webkit-scrollbar, .layout-tv .smoothScrollY::-webkit-scrollbar, .layout-tv .scrollY::-webkit-scrollbar { width: 0 !important; - display: none + display: none; } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/search/searchfields.css b/src/bower_components/emby-webcomponents/search/searchfields.css index 114f25a2ae..4dea76771b 100644 --- a/src/bower_components/emby-webcomponents/search/searchfields.css +++ b/src/bower_components/emby-webcomponents/search/searchfields.css @@ -1,12 +1,11 @@ -.searchFieldsInner { +.searchFieldsInner { max-width: 60em; - margin: 0 auto + margin: 0 auto; } .searchfields-icon { margin-bottom: .1em; margin-right: .25em; font-size: 2em; - -webkit-align-self: flex-end; - align-self: flex-end -} \ No newline at end of file + align-self: flex-end; +} diff --git a/src/bower_components/emby-webcomponents/search/searchfields.js b/src/bower_components/emby-webcomponents/search/searchfields.js index e52fd7ef24..7468dffbd9 100644 --- a/src/bower_components/emby-webcomponents/search/searchfields.js +++ b/src/bower_components/emby-webcomponents/search/searchfields.js @@ -1,64 +1,124 @@ -define(["layoutManager", "globalize", "require", "events", "browser", "alphaPicker", "emby-input", "flexStyles", "material-icons", "css!./searchfields"], function(layoutManager, globalize, require, events, browser, AlphaPicker) { - "use strict"; +define(['layoutManager', 'globalize', 'require', 'events', 'browser', 'alphaPicker', 'emby-input', 'flexStyles', 'material-icons', 'css!./searchfields'], function (layoutManager, globalize, require, events, browser, AlphaPicker) { + 'use strict'; function onSearchTimeout() { - var instance = this, - value = instance.nextSearchValue; - value = (value || "").trim(), events.trigger(instance, "search", [value]) + + var instance = this; + var value = instance.nextSearchValue; + + value = (value || '').trim(); + events.trigger(instance, 'search', [value]); } function triggerSearch(instance, value) { - instance.searchTimeout && clearTimeout(instance.searchTimeout), instance.nextSearchValue = value, instance.searchTimeout = setTimeout(onSearchTimeout.bind(instance), 400) + + if (instance.searchTimeout) { + clearTimeout(instance.searchTimeout); + } + + instance.nextSearchValue = value; + instance.searchTimeout = setTimeout(onSearchTimeout.bind(instance), 400); } function onAlphaValueClicked(e) { - var value = e.detail.value, - searchFieldsInstance = this, - txtSearch = searchFieldsInstance.options.element.querySelector(".searchfields-txtSearch"); - if ("backspace" === value) { + + var value = e.detail.value; + var searchFieldsInstance = this; + + var txtSearch = searchFieldsInstance.options.element.querySelector('.searchfields-txtSearch'); + + if (value === 'backspace') { + var val = txtSearch.value; - txtSearch.value = val.length ? val.substring(0, val.length - 1) : "" - } else txtSearch.value += value; - txtSearch.dispatchEvent(new CustomEvent("input", { - bubbles: !0 - })) + txtSearch.value = val.length ? val.substring(0, val.length - 1) : ''; + + } else { + txtSearch.value += value; + } + + txtSearch.dispatchEvent(new CustomEvent('input', { + bubbles: true + })); } function initAlphaPicker(alphaPickerElement, instance) { + instance.alphaPicker = new AlphaPicker({ element: alphaPickerElement, - mode: "keyboard" - }), alphaPickerElement.addEventListener("alphavalueclicked", onAlphaValueClicked.bind(instance)) + mode: 'keyboard' + }); + + alphaPickerElement.addEventListener('alphavalueclicked', onAlphaValueClicked.bind(instance)); } function onSearchInput(e) { - triggerSearch(this, e.target.value) + + var value = e.target.value; + var searchFieldsInstance = this; + triggerSearch(searchFieldsInstance, value); } function embed(elem, instance, options) { - require(["text!./searchfields.template.html"], function(template) { - var html = globalize.translateDocument(template, "sharedcomponents"); - (browser.tizen || browser.orsay) && (html = html.replace("'; - return itemHtml += i.Name, itemHtml += "
    " - }).join(""), - searchSuggestions = context.querySelector(".searchSuggestions"); - searchSuggestions.querySelector(".searchSuggestionsList").innerHTML = html, result.Items.length && searchSuggestions.classList.remove("hide") - }) + + apiClient.getItems(apiClient.getCurrentUserId(), options).then(function (result) { + + if (instance.mode !== 'suggestions') { + result.Items = []; + } + + var html = result.Items.map(function (i) { + + var href = appRouter.getRouteUrl(i); + + var itemHtml = ''; + return itemHtml; + + }).join(''); + + var searchSuggestions = context.querySelector('.searchSuggestions'); + searchSuggestions.querySelector('.searchSuggestionsList').innerHTML = html; + + if (result.Items.length) { + searchSuggestions.classList.remove('hide'); + } + }); } function getSearchHints(instance, apiClient, query) { - if (!query.searchTerm) return Promise.resolve({ - SearchHints: [] - }); - var allowSearch = !0, - queryIncludeItemTypes = query.IncludeItemTypes; - if ("tvshows" === instance.options.collectionType ? query.IncludeArtists ? allowSearch = !1 : "Movie" !== queryIncludeItemTypes && "LiveTvProgram" !== queryIncludeItemTypes && "MusicAlbum" !== queryIncludeItemTypes && "Audio" !== queryIncludeItemTypes && "Book" !== queryIncludeItemTypes && "AudioBook" !== queryIncludeItemTypes && "Playlist" !== queryIncludeItemTypes && "PhotoAlbum" !== queryIncludeItemTypes && "Video" !== query.MediaTypes && "Photo" !== query.MediaTypes || (allowSearch = !1) : "movies" === instance.options.collectionType ? query.IncludeArtists ? allowSearch = !1 : "Series" !== queryIncludeItemTypes && "Episode" !== queryIncludeItemTypes && "LiveTvProgram" !== queryIncludeItemTypes && "MusicAlbum" !== queryIncludeItemTypes && "Audio" !== queryIncludeItemTypes && "Book" !== queryIncludeItemTypes && "AudioBook" !== queryIncludeItemTypes && "Playlist" !== queryIncludeItemTypes && "PhotoAlbum" !== queryIncludeItemTypes && "Video" !== query.MediaTypes && "Photo" !== query.MediaTypes || (allowSearch = !1) : "music" === instance.options.collectionType ? query.People ? allowSearch = !1 : "Series" !== queryIncludeItemTypes && "Episode" !== queryIncludeItemTypes && "LiveTvProgram" !== queryIncludeItemTypes && "Movie" !== queryIncludeItemTypes || (allowSearch = !1) : "livetv" === instance.options.collectionType && (query.IncludeArtists || query.IncludePeople ? allowSearch = !1 : "Series" !== queryIncludeItemTypes && "Episode" !== queryIncludeItemTypes && "MusicAlbum" !== queryIncludeItemTypes && "Audio" !== queryIncludeItemTypes && "Book" !== queryIncludeItemTypes && "AudioBook" !== queryIncludeItemTypes && "PhotoAlbum" !== queryIncludeItemTypes && "Movie" !== queryIncludeItemTypes && "Video" !== query.MediaTypes && "Photo" !== query.MediaTypes || (allowSearch = !1)), "NullType" === queryIncludeItemTypes && (allowSearch = !1), !allowSearch) return Promise.resolve({ - SearchHints: [] - }); - if (apiClient.isMinServerVersion("3.4.1.31")) { - query.Fields = "PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount", query.Recursive = !0, query.EnableTotalRecordCount = !1, query.ImageTypeLimit = 1; - var methodName = "getItems"; - return query.IncludeMedia || (query.IncludePeople ? methodName = "getPeople" : query.IncludeArtists && (methodName = "getArtists")), apiClient[methodName](apiClient.getCurrentUserId(), query) + + if (!query.searchTerm) { + return Promise.resolve({ + SearchHints: [] + }); } - return query.UserId = apiClient.getCurrentUserId(), apiClient.getSearchHints(query) + + var allowSearch = true; + + var queryIncludeItemTypes = query.IncludeItemTypes; + + if (instance.options.collectionType === 'tvshows') { + if (query.IncludeArtists) { + allowSearch = false; + } + else if (queryIncludeItemTypes === 'Movie' || + queryIncludeItemTypes === 'LiveTvProgram' || + queryIncludeItemTypes === 'MusicAlbum' || + queryIncludeItemTypes === 'Audio' || + queryIncludeItemTypes === 'Book' || + queryIncludeItemTypes === 'AudioBook' || + queryIncludeItemTypes === 'Playlist' || + queryIncludeItemTypes === 'PhotoAlbum' || + query.MediaTypes === 'Video' || + query.MediaTypes === 'Photo') { + allowSearch = false; + } + } + else if (instance.options.collectionType === 'movies') { + if (query.IncludeArtists) { + allowSearch = false; + } + else if (queryIncludeItemTypes === 'Series' || + queryIncludeItemTypes === 'Episode' || + queryIncludeItemTypes === 'LiveTvProgram' || + queryIncludeItemTypes === 'MusicAlbum' || + queryIncludeItemTypes === 'Audio' || + queryIncludeItemTypes === 'Book' || + queryIncludeItemTypes === 'AudioBook' || + queryIncludeItemTypes === 'Playlist' || + queryIncludeItemTypes === 'PhotoAlbum' || + query.MediaTypes === 'Video' || + query.MediaTypes === 'Photo') { + allowSearch = false; + } + } + else if (instance.options.collectionType === 'music') { + if (query.People) { + allowSearch = false; + } + else if (queryIncludeItemTypes === 'Series' || + queryIncludeItemTypes === 'Episode' || + queryIncludeItemTypes === 'LiveTvProgram' || + queryIncludeItemTypes === 'Movie') { + allowSearch = false; + } + } + else if (instance.options.collectionType === 'livetv') { + if (query.IncludeArtists || query.IncludePeople) { + allowSearch = false; + } + else if (queryIncludeItemTypes === 'Series' || + queryIncludeItemTypes === 'Episode' || + queryIncludeItemTypes === 'MusicAlbum' || + queryIncludeItemTypes === 'Audio' || + queryIncludeItemTypes === 'Book' || + queryIncludeItemTypes === 'AudioBook' || + queryIncludeItemTypes === 'PhotoAlbum' || + queryIncludeItemTypes === 'Movie' || + query.MediaTypes === 'Video' || + query.MediaTypes === 'Photo') { + allowSearch = false; + } + } + if (queryIncludeItemTypes === 'NullType') { + allowSearch = false; + } + + if (!allowSearch) { + return Promise.resolve({ + SearchHints: [] + }); + } + + // Convert the search hint query to a regular item query + if (apiClient.isMinServerVersion('3.4.1.31')) { + + query.Fields = 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount'; + query.Recursive = true; + query.EnableTotalRecordCount = false; + query.ImageTypeLimit = 1; + + var methodName = 'getItems'; + + if (!query.IncludeMedia) { + if (query.IncludePeople) { + methodName = 'getPeople'; + + } else if (query.IncludeArtists) { + methodName = 'getArtists'; + } + } + + return apiClient[methodName](apiClient.getCurrentUserId(), query); + } + + query.UserId = apiClient.getCurrentUserId(); + + return apiClient.getSearchHints(query); } function search(instance, apiClient, context, value) { - value || layoutManager.tv ? (instance.mode = "search", context.querySelector(".searchSuggestions").classList.add("hide")) : (instance.mode = "suggestions", loadSuggestions(instance, context, apiClient)), "livetv" === instance.options.collectionType ? searchType(instance, apiClient, { + + if (value || layoutManager.tv) { + instance.mode = 'search'; + context.querySelector('.searchSuggestions').classList.add('hide'); + } else { + instance.mode = 'suggestions'; + loadSuggestions(instance, context, apiClient); + } + + if (instance.options.collectionType === 'livetv') { + + searchType(instance, apiClient, { + searchTerm: value, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, + IncludeItemTypes: "LiveTvProgram", + IsMovie: true, + IsKids: false, + IsNews: false + + }, context, '.movieResults', { + + preferThumb: true, + inheritThumb: false, + shape: (enableScrollX() ? 'overflowPortrait' : 'portrait'), + showParentTitleOrTitle: true, + showTitle: false, + centerText: true, + coverImage: true, + overlayText: false, + overlayMoreButton: true, + showAirTime: true, + showAirDateTime: true, + showChannelName: true + }); + } else { + + searchType(instance, apiClient, { + searchTerm: value, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, + IncludeItemTypes: "Movie" + + }, context, '.movieResults', { + + showTitle: true, + overlayText: false, + centerText: true, + showYear: true + }); + } + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, - IncludeItemTypes: "LiveTvProgram", - IsMovie: !0, - IsKids: !1, - IsNews: !1 - }, context, ".movieResults", { - preferThumb: !0, - inheritThumb: !1, - shape: enableScrollX() ? "overflowPortrait" : "portrait", - showParentTitleOrTitle: !0, - showTitle: !1, - centerText: !0, - coverImage: !0, - overlayText: !1, - overlayMoreButton: !0, - showAirTime: !0, - showAirDateTime: !0, - showChannelName: !0 - }) : searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, - IncludeItemTypes: "Movie" - }, context, ".movieResults", { - showTitle: !0, - overlayText: !1, - centerText: !0, - showYear: !0 - }), searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, IncludeItemTypes: "Series" - }, context, ".seriesResults", { - showTitle: !0, - overlayText: !1, - centerText: !0, - showYear: !0 - }), "livetv" === instance.options.collectionType ? searchType(instance, apiClient, { + + }, context, '.seriesResults', { + + showTitle: true, + overlayText: false, + centerText: true, + showYear: true + }); + + if (instance.options.collectionType === 'livetv') { + + searchType(instance, apiClient, { + searchTerm: value, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, + IncludeItemTypes: "LiveTvProgram", + IsSeries: true, + IsSports: false, + IsKids: false, + IsNews: false + + }, context, '.episodeResults', { + + preferThumb: true, + inheritThumb: false, + shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'), + showParentTitleOrTitle: true, + showTitle: false, + centerText: true, + coverImage: true, + overlayText: false, + overlayMoreButton: true, + showAirTime: true, + showAirDateTime: true, + showChannelName: true + }); + + } else { + + searchType(instance, apiClient, { + searchTerm: value, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, + IncludeItemTypes: "Episode" + + }, context, '.episodeResults', { + + coverImage: true, + showTitle: true, + showParentTitle: true + }); + } + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, + // NullType to hide + IncludeItemTypes: instance.options.collectionType === 'livetv' ? 'LiveTvProgram' : 'NullType', + IsSports: true + + }, context, '.sportsResults', { + + preferThumb: true, + inheritThumb: false, + shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'), + showParentTitleOrTitle: true, + showTitle: false, + centerText: true, + coverImage: true, + overlayText: false, + overlayMoreButton: true, + showAirTime: true, + showAirDateTime: true, + showChannelName: true + + }); + + searchType(instance, apiClient, { + searchTerm: value, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, + // NullType to hide + IncludeItemTypes: instance.options.collectionType === 'livetv' ? 'LiveTvProgram' : 'NullType', + IsKids: true + + }, context, '.kidsResults', { + + preferThumb: true, + inheritThumb: false, + shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'), + showParentTitleOrTitle: true, + showTitle: false, + centerText: true, + coverImage: true, + overlayText: false, + overlayMoreButton: true, + showAirTime: true, + showAirDateTime: true, + showChannelName: true + + }); + + searchType(instance, apiClient, { + searchTerm: value, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, + // NullType to hide + IncludeItemTypes: instance.options.collectionType === 'livetv' ? 'LiveTvProgram' : 'NullType', + IsNews: true + + }, context, '.newsResults', { + + preferThumb: true, + inheritThumb: false, + shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'), + showParentTitleOrTitle: true, + showTitle: false, + centerText: true, + coverImage: true, + overlayText: false, + overlayMoreButton: true, + showAirTime: true, + showAirDateTime: true, + showChannelName: true + + }); + + searchType(instance, apiClient, { + searchTerm: value, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, IncludeItemTypes: "LiveTvProgram", - IsSeries: !0, - IsSports: !1, - IsKids: !1, - IsNews: !1 - }, context, ".episodeResults", { - preferThumb: !0, - inheritThumb: !1, - shape: enableScrollX() ? "overflowBackdrop" : "backdrop", - showParentTitleOrTitle: !0, - showTitle: !1, - centerText: !0, - coverImage: !0, - overlayText: !1, - overlayMoreButton: !0, - showAirTime: !0, - showAirDateTime: !0, - showChannelName: !0 - }) : searchType(instance, apiClient, { + IsMovie: instance.options.collectionType === 'livetv' ? false : null, + IsSeries: instance.options.collectionType === 'livetv' ? false : null, + IsSports: instance.options.collectionType === 'livetv' ? false : null, + IsKids: instance.options.collectionType === 'livetv' ? false : null, + IsNews: instance.options.collectionType === 'livetv' ? false : null + + }, context, '.programResults', { + + preferThumb: true, + inheritThumb: false, + shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'), + showParentTitleOrTitle: true, + showTitle: false, + centerText: true, + coverImage: true, + overlayText: false, + overlayMoreButton: true, + showAirTime: true, + showAirDateTime: true, + showChannelName: true + + }); + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, - IncludeItemTypes: "Episode" - }, context, ".episodeResults", { - coverImage: !0, - showTitle: !0, - showParentTitle: !0 - }), searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, - IncludeItemTypes: "livetv" === instance.options.collectionType ? "LiveTvProgram" : "NullType", - IsSports: !0 - }, context, ".sportsResults", { - preferThumb: !0, - inheritThumb: !1, - shape: enableScrollX() ? "overflowBackdrop" : "backdrop", - showParentTitleOrTitle: !0, - showTitle: !1, - centerText: !0, - coverImage: !0, - overlayText: !1, - overlayMoreButton: !0, - showAirTime: !0, - showAirDateTime: !0, - showChannelName: !0 - }), searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, - IncludeItemTypes: "livetv" === instance.options.collectionType ? "LiveTvProgram" : "NullType", - IsKids: !0 - }, context, ".kidsResults", { - preferThumb: !0, - inheritThumb: !1, - shape: enableScrollX() ? "overflowBackdrop" : "backdrop", - showParentTitleOrTitle: !0, - showTitle: !1, - centerText: !0, - coverImage: !0, - overlayText: !1, - overlayMoreButton: !0, - showAirTime: !0, - showAirDateTime: !0, - showChannelName: !0 - }), searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, - IncludeItemTypes: "livetv" === instance.options.collectionType ? "LiveTvProgram" : "NullType", - IsNews: !0 - }, context, ".newsResults", { - preferThumb: !0, - inheritThumb: !1, - shape: enableScrollX() ? "overflowBackdrop" : "backdrop", - showParentTitleOrTitle: !0, - showTitle: !1, - centerText: !0, - coverImage: !0, - overlayText: !1, - overlayMoreButton: !0, - showAirTime: !0, - showAirDateTime: !0, - showChannelName: !0 - }), searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, - IncludeItemTypes: "LiveTvProgram", - IsMovie: "livetv" !== instance.options.collectionType && null, - IsSeries: "livetv" !== instance.options.collectionType && null, - IsSports: "livetv" !== instance.options.collectionType && null, - IsKids: "livetv" !== instance.options.collectionType && null, - IsNews: "livetv" !== instance.options.collectionType && null - }, context, ".programResults", { - preferThumb: !0, - inheritThumb: !1, - shape: enableScrollX() ? "overflowBackdrop" : "backdrop", - showParentTitleOrTitle: !0, - showTitle: !1, - centerText: !0, - coverImage: !0, - overlayText: !1, - overlayMoreButton: !0, - showAirTime: !0, - showAirDateTime: !0, - showChannelName: !0 - }), searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, MediaTypes: "Video", ExcludeItemTypes: "Movie,Episode" - }, context, ".videoResults", { - showParentTitle: !0, - showTitle: !0, - overlayText: !1, - centerText: !0 - }), searchType(instance, apiClient, { + + }, context, '.videoResults', { + + showParentTitle: true, + showTitle: true, + overlayText: false, + centerText: true + }); + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !0, - IncludeMedia: !1, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1 - }, context, ".peopleResults", { - coverImage: !0, - showTitle: !0 - }), searchType(instance, apiClient, { + IncludePeople: true, + IncludeMedia: false, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false + + }, context, '.peopleResults', { + + coverImage: true, + showTitle: true + }); + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !1, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !0 - }, context, ".artistResults", { - coverImage: !0, - showTitle: !0 - }), searchType(instance, apiClient, { + IncludePeople: false, + IncludeMedia: false, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: true + + }, context, '.artistResults', { + coverImage: true, + showTitle: true + }); + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, IncludeItemTypes: "MusicAlbum" - }, context, ".albumResults", { - showParentTitle: !0, - showTitle: !0, - overlayText: !1, - centerText: !0 - }), searchType(instance, apiClient, { + + }, context, '.albumResults', { + + showParentTitle: true, + showTitle: true, + overlayText: false, + centerText: true + }); + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, IncludeItemTypes: "Audio" - }, context, ".songResults", { - showParentTitle: !0, - showTitle: !0, - overlayText: !1, - centerText: !0, - action: "play" - }), searchType(instance, apiClient, { + + }, context, '.songResults', { + + showParentTitle: true, + showTitle: true, + overlayText: false, + centerText: true, + action: 'play' + + }); + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, MediaTypes: "Photo" - }, context, ".photoResults", { - showParentTitle: !1, - showTitle: !0, - overlayText: !1, - centerText: !0 - }), searchType(instance, apiClient, { + + }, context, '.photoResults', { + + showParentTitle: false, + showTitle: true, + overlayText: false, + centerText: true + }); + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, IncludeItemTypes: "PhotoAlbum" - }, context, ".photoAlbumResults", { - showTitle: !0, - overlayText: !1, - centerText: !0 - }), searchType(instance, apiClient, { + + }, context, '.photoAlbumResults', { + + showTitle: true, + overlayText: false, + centerText: true + }); + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, IncludeItemTypes: "Book" - }, context, ".bookResults", { - showTitle: !0, - overlayText: !1, - centerText: !0 - }), searchType(instance, apiClient, { + + }, context, '.bookResults', { + + showTitle: true, + overlayText: false, + centerText: true + + }); + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, IncludeItemTypes: "AudioBook" - }, context, ".audioBookResults", { - showTitle: !0, - overlayText: !1, - centerText: !0 - }), searchType(instance, apiClient, { + + }, context, '.audioBookResults', { + + showTitle: true, + overlayText: false, + centerText: true + }); + + searchType(instance, apiClient, { searchTerm: value, - IncludePeople: !1, - IncludeMedia: !0, - IncludeGenres: !1, - IncludeStudios: !1, - IncludeArtists: !1, + IncludePeople: false, + IncludeMedia: true, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false, IncludeItemTypes: "Playlist" - }, context, ".playlistResults", { - showTitle: !0, - overlayText: !1, - centerText: !0 - }) + + }, context, '.playlistResults', { + + showTitle: true, + overlayText: false, + centerText: true + }); } function searchType(instance, apiClient, query, context, section, cardOptions) { - query.Limit = enableScrollX() ? 24 : 16, query.ParentId = instance.options.parentId, getSearchHints(instance, apiClient, query).then(function(result) { - populateResults(result, context, section, cardOptions) - }) + + query.Limit = enableScrollX() ? 24 : 16; + query.ParentId = instance.options.parentId; + + getSearchHints(instance, apiClient, query).then(function (result) { + + populateResults(result, context, section, cardOptions); + }); } function populateResults(result, context, section, cardOptions) { + section = context.querySelector(section); - var items = result.Items || result.SearchHints, - itemsContainer = section.querySelector(".itemsContainer"); + + var items = result.Items || result.SearchHints; + + var itemsContainer = section.querySelector('.itemsContainer'); + cardBuilder.buildCards(items, Object.assign({ + itemsContainer: itemsContainer, parentContainer: section, - shape: enableScrollX() ? "autooverflow" : "auto", - scalable: !0, - overlayText: !1, - centerText: !0, + shape: enableScrollX() ? 'autooverflow' : 'auto', + scalable: true, + overlayText: false, + centerText: true, allowBottomPadding: !enableScrollX() - }, cardOptions || {})), section.querySelector(".emby-scroller").scrollToBeginning(!0) + + }, cardOptions || {})); + + section.querySelector('.emby-scroller').scrollToBeginning(true); } function enableScrollX() { - return !0 + return true; } function replaceAll(originalString, strReplace, strWith) { - var reg = new RegExp(strReplace, "ig"); - return originalString.replace(reg, strWith) + var reg = new RegExp(strReplace, 'ig'); + return originalString.replace(reg, strWith); } function embed(elem, instance, options) { - require(["text!./searchresults.template.html"], function(template) { - enableScrollX() || (template = replaceAll(template, 'data-horizontal="true"', 'data-horizontal="false"'), template = replaceAll(template, "itemsContainer scrollSlider", "itemsContainer scrollSlider vertical-wrap")); - var html = globalize.translateDocument(template, "sharedcomponents"); - elem.innerHTML = html, elem.classList.add("searchResults"), instance.search("") - }) + + require(['text!./searchresults.template.html'], function (template) { + + if (!enableScrollX()) { + template = replaceAll(template, 'data-horizontal="true"', 'data-horizontal="false"'); + template = replaceAll(template, 'itemsContainer scrollSlider', 'itemsContainer scrollSlider vertical-wrap'); + } + + var html = globalize.translateDocument(template, 'sharedcomponents'); + + elem.innerHTML = html; + + elem.classList.add('searchResults'); + instance.search(''); + }); } function SearchResults(options) { - this.options = options, embed(options.element, this, options) + + this.options = options; + embed(options.element, this, options); } - return SearchResults.prototype.search = function(value) { - search(this, connectionManager.getApiClient(this.options.serverId), this.options.element, value) - }, SearchResults.prototype.destroy = function() { + + SearchResults.prototype.search = function (value) { + + var apiClient = connectionManager.getApiClient(this.options.serverId); + + search(this, apiClient, this.options.element, value); + }; + + SearchResults.prototype.destroy = function () { + var options = this.options; - options && options.element.classList.remove("searchFields"), this.options = null - }, SearchResults + if (options) { + options.element.classList.remove('searchFields'); + } + this.options = null; + + }; + + return SearchResults; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/serverrestartdialog/serverrestartdialog.js b/src/bower_components/emby-webcomponents/serverrestartdialog/serverrestartdialog.js index a86fa3ef16..70747ee804 100644 --- a/src/bower_components/emby-webcomponents/serverrestartdialog/serverrestartdialog.js +++ b/src/bower_components/emby-webcomponents/serverrestartdialog/serverrestartdialog.js @@ -1,70 +1,173 @@ -define(["loading", "events", "dialogHelper", "dom", "layoutManager", "scrollHelper", "globalize", "require", "material-icons", "emby-button", "paper-icon-button-light", "emby-input", "formDialogStyle", "flexStyles"], function(loading, events, dialogHelper, dom, layoutManager, scrollHelper, globalize, require) { - "use strict"; +define(['loading', 'events', 'dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (loading, events, dialogHelper, dom, layoutManager, scrollHelper, globalize, require) { + 'use strict'; + + var currentApiClient; + var currentDlg; + var currentInstance; function reloadPageWhenServerAvailable(retryCount) { + var apiClient = currentApiClient; - apiClient && apiClient.getJSON(apiClient.getUrl("System/Info")).then(function(info) { - info.IsShuttingDown ? retryReload(retryCount) : (currentInstance.restarted = !0, dialogHelper.close(currentDlg)) - }, function() { - retryReload(retryCount) - }) + + if (!apiClient) { + return; + } + + // Don't use apiclient method because we don't want it reporting authentication under the old version + apiClient.getJSON(apiClient.getUrl("System/Info")).then(function (info) { + + // If this is back to false, the restart completed + if (!info.IsShuttingDown) { + currentInstance.restarted = true; + dialogHelper.close(currentDlg); + } else { + retryReload(retryCount); + } + + }, function () { + retryReload(retryCount); + }); } function retryReload(retryCount) { - setTimeout(function() { - retryCount = retryCount || 0, ++retryCount < 150 && reloadPageWhenServerAvailable(retryCount) - }, 500) + setTimeout(function () { + + retryCount = retryCount || 0; + retryCount++; + + if (retryCount < 150) { + reloadPageWhenServerAvailable(retryCount); + } + }, 500); } function startRestart(instance, apiClient, dlg) { - currentApiClient = apiClient, currentDlg = dlg, currentInstance = instance, apiClient.restartServer().then(function() { - setTimeout(reloadPageWhenServerAvailable, 250) - }) + + currentApiClient = apiClient; + currentDlg = dlg; + currentInstance = instance; + + apiClient.restartServer().then(function () { + + setTimeout(reloadPageWhenServerAvailable, 250); + + }); } function showDialog(instance, options, template) { - function onButtonClick() { - dialogHelper.close(dlg) - } + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 - }, - enableTvLayout = layoutManager.tv; - enableTvLayout && (dialogOptions.size = "fullscreen"); - var dlg = dialogHelper.createDialog(dialogOptions), - configuredButtons = []; - dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateHtml(template, "sharedcomponents"), dlg.classList.add("align-items-center"), dlg.classList.add("justify-items-center"); - var formDialogContent = dlg.querySelector(".formDialogContent"); - formDialogContent.style["flex-grow"] = "initial", enableTvLayout ? (formDialogContent.style["max-width"] = "50%", formDialogContent.style["max-height"] = "60%", scrollHelper.centerFocus.on(formDialogContent, !1)) : (formDialogContent.style.maxWidth = Math.min(150 * configuredButtons.length + 200, dom.getWindowSize().innerWidth - 50) + "px", dlg.classList.add("dialog-fullscreen-lowres")), dlg.querySelector(".formDialogHeaderTitle").innerHTML = globalize.translate("sharedcomponents#HeaderRestartingEmbyServer"), dlg.querySelector(".text").innerHTML = globalize.translate("sharedcomponents#RestartPleaseWaitMessage"); - var i, length, html = ""; - for (i = 0, length = configuredButtons.length; i < length; i++) { - var item = configuredButtons[i], - autoFocus = 0 === i ? " autofocus" : "", - buttonClass = "btnOption raised formDialogFooterItem formDialogFooterItem-autosize"; - item.type && (buttonClass += " button-" + item.type), html += '" + removeOnClose: true, + scrollY: false + }; + + var enableTvLayout = layoutManager.tv; + + if (enableTvLayout) { + dialogOptions.size = 'fullscreen'; } - dlg.querySelector(".formDialogFooter").innerHTML = html; - var buttons = dlg.querySelectorAll(".btnOption"); - for (i = 0, length = buttons.length; i < length; i++) buttons[i].addEventListener("click", onButtonClick); + + var dlg = dialogHelper.createDialog(dialogOptions); + + var configuredButtons = []; + + dlg.classList.add('formDialog'); + + dlg.innerHTML = globalize.translateHtml(template, 'sharedcomponents'); + + dlg.classList.add('align-items-center'); + dlg.classList.add('justify-items-center'); + + var formDialogContent = dlg.querySelector('.formDialogContent'); + formDialogContent.style['flex-grow'] = 'initial'; + + if (enableTvLayout) { + formDialogContent.style['max-width'] = '50%'; + formDialogContent.style['max-height'] = '60%'; + scrollHelper.centerFocus.on(formDialogContent, false); + } else { + formDialogContent.style.maxWidth = (Math.min((configuredButtons.length * 150) + 200, dom.getWindowSize().innerWidth - 50)) + 'px'; + dlg.classList.add('dialog-fullscreen-lowres'); + } + + //dlg.querySelector('.btnCancel').addEventListener('click', function (e) { + // dialogHelper.close(dlg); + //}); + + dlg.querySelector('.formDialogHeaderTitle').innerHTML = globalize.translate('sharedcomponents#HeaderRestartingEmbyServer'); + + dlg.querySelector('.text').innerHTML = globalize.translate('sharedcomponents#RestartPleaseWaitMessage'); + + var i, length; + var html = ''; + for (i = 0, length = configuredButtons.length; i < length; i++) { + + var item = configuredButtons[i]; + var autoFocus = i === 0 ? ' autofocus' : ''; + + var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize'; + + if (item.type) { + buttonClass += ' button-' + item.type; + } + + html += ''; + } + + dlg.querySelector('.formDialogFooter').innerHTML = html; + + function onButtonClick() { + dialogHelper.close(dlg); + } + + var buttons = dlg.querySelectorAll('.btnOption'); + for (i = 0, length = buttons.length; i < length; i++) { + buttons[i].addEventListener('click', onButtonClick); + } + var dlgPromise = dialogHelper.open(dlg); - return startRestart(instance, options.apiClient, dlg), dlgPromise.then(function() { - enableTvLayout && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), instance.destroy(), loading.hide(), instance.restarted && events.trigger(instance, "restarted") - }) + + startRestart(instance, options.apiClient, dlg); + + return dlgPromise.then(function () { + + if (enableTvLayout) { + scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); + } + + instance.destroy(); + loading.hide(); + + if (instance.restarted) { + events.trigger(instance, 'restarted'); + } + }); } function ServerRestartDialog(options) { - this.options = options + + this.options = options; } - var currentApiClient, currentDlg, currentInstance; - return ServerRestartDialog.prototype.show = function() { + + ServerRestartDialog.prototype.show = function () { + var instance = this; - return loading.show(), new Promise(function(resolve, reject) { - require(["text!./../dialog/dialog.template.html"], function(template) { - showDialog(instance, instance.options, template).then(resolve, reject) - }) - }) - }, ServerRestartDialog.prototype.destroy = function() { - currentApiClient = null, currentDlg = null, currentInstance = null, this.options = null - }, ServerRestartDialog + loading.show(); + + return new Promise(function (resolve, reject) { + require(['text!./../dialog/dialog.template.html'], function (template) { + showDialog(instance, instance.options, template).then(resolve, reject); + }); + }); + }; + + ServerRestartDialog.prototype.destroy = function () { + + currentApiClient = null; + currentDlg = null; + currentInstance = null; + this.options = null; + }; + + return ServerRestartDialog; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/serviceworker/notifications.js b/src/bower_components/emby-webcomponents/serviceworker/notifications.js index e99b2f44c1..c566715bb7 100644 --- a/src/bower_components/emby-webcomponents/serviceworker/notifications.js +++ b/src/bower_components/emby-webcomponents/serviceworker/notifications.js @@ -1,31 +1,52 @@ -! function() { - "use strict"; +(function () { + 'use strict'; + + var connectionManager; function getApiClient(serverId) { - return connectionManager ? Promise.resolve(connectionManager.getApiClient(serverId)) : Promise.reject() + + if (connectionManager) { + return Promise.resolve(connectionManager.getApiClient(serverId)); + } + + //importScripts('serviceworker-cache-polyfill.js'); + + return Promise.reject(); } function executeAction(action, data, serverId) { - return getApiClient(serverId).then(function(apiClient) { + + return getApiClient(serverId).then(function (apiClient) { + switch (action) { - case "cancel-install": + case 'cancel-install': var id = data.id; return apiClient.cancelPackageInstallation(id); - case "restart": + case 'restart': return apiClient.restartServer(); default: - return clients.openWindow("/"), Promise.resolve() + clients.openWindow("/"); + return Promise.resolve(); } - }) + }); } - var connectionManager; - self.addEventListener("notificationclick", function(event) { + + self.addEventListener('notificationclick', function (event) { + var notification = event.notification; notification.close(); - var data = notification.data, - serverId = data.serverId, - action = event.action; - if (!action) return clients.openWindow("/"), void event.waitUntil(Promise.resolve()); - event.waitUntil(executeAction(action, data, serverId)) - }, !1) -}(); \ No newline at end of file + + var data = notification.data; + var serverId = data.serverId; + var action = event.action; + + if (!action) { + clients.openWindow("/"); + event.waitUntil(Promise.resolve()); + return; + } + + event.waitUntil(executeAction(action, data, serverId)); + + }, false); +})(); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/serviceworker/sync.js b/src/bower_components/emby-webcomponents/serviceworker/sync.js index 5fdaac113d..3dcff8f363 100644 --- a/src/bower_components/emby-webcomponents/serviceworker/sync.js +++ b/src/bower_components/emby-webcomponents/serviceworker/sync.js @@ -1,4 +1,6 @@ -self.addEventListener("sync", function(event) { - "use strict"; - event.tag +self.addEventListener('sync', function (event) { + 'use strict'; + + if (event.tag === 'emby-sync') { + } }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/sessionplayer.js b/src/bower_components/emby-webcomponents/sessionplayer.js index f7c45f561a..0b6aa0e54d 100644 --- a/src/bower_components/emby-webcomponents/sessionplayer.js +++ b/src/bower_components/emby-webcomponents/sessionplayer.js @@ -1,108 +1,259 @@ -define(["playbackManager", "events", "serverNotifications", "connectionManager"], function(playbackManager, events, serverNotifications, connectionManager) { - "use strict"; +define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'], function (playbackManager, events, serverNotifications, connectionManager) { + 'use strict'; function getActivePlayerId() { var info = playbackManager.getPlayerInfo(); - return info ? info.id : null + return info ? info.id : null; } function sendPlayCommand(apiClient, options, playType) { - var sessionId = getActivePlayerId(), - ids = options.ids || options.items.map(function(i) { - return i.Id - }), - remoteOptions = { - ItemIds: ids.join(","), - PlayCommand: playType - }; - return options.startPositionTicks && (remoteOptions.StartPositionTicks = options.startPositionTicks), options.mediaSourceId && (remoteOptions.MediaSourceId = options.mediaSourceId), null != options.audioStreamIndex && (remoteOptions.AudioStreamIndex = options.audioStreamIndex), null != options.subtitleStreamIndex && (remoteOptions.SubtitleStreamIndex = options.subtitleStreamIndex), null != options.startIndex && (remoteOptions.StartIndex = options.startIndex), apiClient.sendPlayCommand(sessionId, remoteOptions) + + var sessionId = getActivePlayerId(); + + var ids = options.ids || options.items.map(function (i) { + return i.Id; + }); + + var remoteOptions = { + ItemIds: ids.join(','), + + PlayCommand: playType + }; + + if (options.startPositionTicks) { + remoteOptions.StartPositionTicks = options.startPositionTicks; + } + + if (options.mediaSourceId) { + remoteOptions.MediaSourceId = options.mediaSourceId; + } + + if (options.audioStreamIndex != null) { + remoteOptions.AudioStreamIndex = options.audioStreamIndex; + } + + if (options.subtitleStreamIndex != null) { + remoteOptions.SubtitleStreamIndex = options.subtitleStreamIndex; + } + + if (options.startIndex != null) { + remoteOptions.StartIndex = options.startIndex; + } + + return apiClient.sendPlayCommand(sessionId, remoteOptions); } function sendPlayStateCommand(apiClient, command, options) { + var sessionId = getActivePlayerId(); - apiClient.sendPlayStateCommand(sessionId, command, options) + + apiClient.sendPlayStateCommand(sessionId, command, options); } function getCurrentApiClient(instance) { + var currentServerId = instance.currentServerId; - return currentServerId ? connectionManager.getApiClient(currentServerId) : connectionManager.currentApiClient() + + if (currentServerId) { + return connectionManager.getApiClient(currentServerId); + } + + return connectionManager.currentApiClient(); } function sendCommandByName(instance, name, options) { + var command = { Name: name }; - options && (command.Arguments = options), instance.sendCommand(command) + + if (options) { + command.Arguments = options; + } + + instance.sendCommand(command); } function unsubscribeFromPlayerUpdates(instance) { - instance.isUpdating = !0, getCurrentApiClient(instance).sendMessage("SessionsStop"), instance.pollInterval && (clearInterval(instance.pollInterval), instance.pollInterval = null) + + instance.isUpdating = true; + + var apiClient = getCurrentApiClient(instance); + apiClient.sendMessage("SessionsStop"); + if (instance.pollInterval) { + clearInterval(instance.pollInterval); + instance.pollInterval = null; + } } function processUpdatedSessions(instance, sessions, apiClient) { + var serverId = apiClient.serverId(); - sessions.map(function(s) { - s.NowPlayingItem && (s.NowPlayingItem.ServerId = serverId) + + sessions.map(function (s) { + if (s.NowPlayingItem) { + s.NowPlayingItem.ServerId = serverId; + } }); - var currentTargetId = getActivePlayerId(), - session = sessions.filter(function(s) { - return s.Id === currentTargetId - })[0]; + + var currentTargetId = getActivePlayerId(); + + var session = sessions.filter(function (s) { + return s.Id === currentTargetId; + })[0]; + if (session) { + normalizeImages(session, apiClient); + var eventNames = getChangedEvents(instance.lastPlayerData, session); instance.lastPlayerData = session; - for (var i = 0, length = eventNames.length; i < length; i++) events.trigger(instance, eventNames[i], [session]) - } else instance.lastPlayerData = session, playbackManager.setDefaultPlayerActive() + + for (var i = 0, length = eventNames.length; i < length; i++) { + events.trigger(instance, eventNames[i], [session]); + } + + } else { + + instance.lastPlayerData = session; + + playbackManager.setDefaultPlayerActive(); + } } function getChangedEvents(state1, state2) { + var names = []; - return names.push("statechange"), names.push("timeupdate"), names.push("pause"), names + + if (!state1) { + names.push('statechange'); + names.push('timeupdate'); + names.push('pause'); + + return names; + } + + // TODO: Trim these down to prevent the UI from over-refreshing + names.push('statechange'); + names.push('timeupdate'); + names.push('pause'); + + return names; } function onPollIntervalFired() { - var instance = this, - apiClient = getCurrentApiClient(instance); - apiClient.isMessageChannelOpen() || apiClient.getSessions().then(function(sessions) { - processUpdatedSessions(instance, sessions, apiClient) - }) + + var instance = this; + var apiClient = getCurrentApiClient(instance); + if (!apiClient.isMessageChannelOpen()) { + + apiClient.getSessions().then(function (sessions) { + processUpdatedSessions(instance, sessions, apiClient); + }); + } } function subscribeToPlayerUpdates(instance) { - instance.isUpdating = !0, getCurrentApiClient(instance).sendMessage("SessionsStart", "100,800"), instance.pollInterval && (clearInterval(instance.pollInterval), instance.pollInterval = null), instance.pollInterval = setInterval(onPollIntervalFired.bind(instance), 5e3) + + instance.isUpdating = true; + + var apiClient = getCurrentApiClient(instance); + apiClient.sendMessage("SessionsStart", "100,800"); + if (instance.pollInterval) { + clearInterval(instance.pollInterval); + instance.pollInterval = null; + } + instance.pollInterval = setInterval(onPollIntervalFired.bind(instance), 5000); } function normalizeImages(state, apiClient) { + if (state && state.NowPlayingItem) { + var item = state.NowPlayingItem; - item.ImageTags && item.ImageTags.Primary || item.PrimaryImageTag && (item.ImageTags = item.ImageTags || {}, item.ImageTags.Primary = item.PrimaryImageTag), item.BackdropImageTag && item.BackdropItemId === item.Id && (item.BackdropImageTags = [item.BackdropImageTag]), item.BackdropImageTag && item.BackdropItemId !== item.Id && (item.ParentBackdropImageTags = [item.BackdropImageTag], item.ParentBackdropItemId = item.BackdropItemId), item.ServerId || (item.ServerId = apiClient.serverId()) + + if (!item.ImageTags || !item.ImageTags.Primary) { + if (item.PrimaryImageTag) { + item.ImageTags = item.ImageTags || {}; + item.ImageTags.Primary = item.PrimaryImageTag; + } + } + if (item.BackdropImageTag && item.BackdropItemId === item.Id) { + item.BackdropImageTags = [item.BackdropImageTag]; + } + if (item.BackdropImageTag && item.BackdropItemId !== item.Id) { + item.ParentBackdropImageTags = [item.BackdropImageTag]; + item.ParentBackdropItemId = item.BackdropItemId; + } + if (!item.ServerId) { + item.ServerId = apiClient.serverId(); + } } } function SessionPlayer() { + var self = this; - this.name = "Remote Control", this.type = "mediaplayer", this.isLocalPlayer = !1, this.id = "remoteplayer", events.on(serverNotifications, "Sessions", function(e, apiClient, data) { - processUpdatedSessions(self, data, apiClient) - }) + + this.name = 'Remote Control'; + this.type = 'mediaplayer'; + this.isLocalPlayer = false; + this.id = 'remoteplayer'; + + events.on(serverNotifications, 'Sessions', function (e, apiClient, data) { + processUpdatedSessions(self, data, apiClient); + }); } - return SessionPlayer.prototype.beginPlayerUpdates = function() { - this.playerListenerCount = this.playerListenerCount || 0, this.playerListenerCount <= 0 && (this.playerListenerCount = 0, subscribeToPlayerUpdates(this)), this.playerListenerCount++ - }, SessionPlayer.prototype.endPlayerUpdates = function() { - this.playerListenerCount = this.playerListenerCount || 0, --this.playerListenerCount <= 0 && (unsubscribeFromPlayerUpdates(this), this.playerListenerCount = 0) - }, SessionPlayer.prototype.getPlayerState = function() { - return this.lastPlayerData || {} - }, SessionPlayer.prototype.getTargets = function() { - var apiClient = getCurrentApiClient(this), - sessionQuery = { - ControllableByUserId: apiClient.getCurrentUserId() - }; + + SessionPlayer.prototype.beginPlayerUpdates = function () { + + this.playerListenerCount = this.playerListenerCount || 0; + + if (this.playerListenerCount <= 0) { + + this.playerListenerCount = 0; + + subscribeToPlayerUpdates(this); + } + + this.playerListenerCount++; + }; + + SessionPlayer.prototype.endPlayerUpdates = function () { + + this.playerListenerCount = this.playerListenerCount || 0; + this.playerListenerCount--; + + if (this.playerListenerCount <= 0) { + + unsubscribeFromPlayerUpdates(this); + this.playerListenerCount = 0; + } + }; + + SessionPlayer.prototype.getPlayerState = function () { + + return this.lastPlayerData || {}; + }; + + SessionPlayer.prototype.getTargets = function () { + + var apiClient = getCurrentApiClient(this); + + var sessionQuery = { + ControllableByUserId: apiClient.getCurrentUserId() + }; + if (apiClient) { + var name = this.name; - return apiClient.getSessions(sessionQuery).then(function(sessions) { - return sessions.filter(function(s) { - return s.DeviceId !== apiClient.deviceId() - }).map(function(s) { + + return apiClient.getSessions(sessionQuery).then(function (sessions) { + + return sessions.filter(function (s) { + return s.DeviceId !== apiClient.deviceId(); + + }).map(function (s) { return { name: s.DeviceName, deviceName: s.DeviceName, @@ -111,136 +262,291 @@ define(["playbackManager", "events", "serverNotifications", "connectionManager"] playerName: name, appName: s.Client, playableMediaTypes: s.PlayableMediaTypes, - isLocalPlayer: !1, + isLocalPlayer: false, supportedCommands: s.SupportedCommands, user: s.UserId ? { + Id: s.UserId, Name: s.UserName, PrimaryImageTag: s.UserPrimaryImageTag + } : null - } - }) - }) + }; + }); + + }); + + } else { + return Promise.resolve([]); } - return Promise.resolve([]) - }, SessionPlayer.prototype.sendCommand = function(command) { + }; + + SessionPlayer.prototype.sendCommand = function (command) { + var sessionId = getActivePlayerId(); - getCurrentApiClient(this).sendCommand(sessionId, command) - }, SessionPlayer.prototype.play = function(options) { - return options = Object.assign({}, options), options.items && (options.ids = options.items.map(function(i) { - return i.Id - }), options.items = null), sendPlayCommand(getCurrentApiClient(this), options, "PlayNow") - }, SessionPlayer.prototype.shuffle = function(item) { - sendPlayCommand(getCurrentApiClient(this), { - ids: [item.Id] - }, "PlayShuffle") - }, SessionPlayer.prototype.instantMix = function(item) { - sendPlayCommand(getCurrentApiClient(this), { - ids: [item.Id] - }, "PlayInstantMix") - }, SessionPlayer.prototype.queue = function(options) { - sendPlayCommand(getCurrentApiClient(this), options, "PlayNext") - }, SessionPlayer.prototype.queueNext = function(options) { - sendPlayCommand(getCurrentApiClient(this), options, "PlayLast") - }, SessionPlayer.prototype.canPlayMediaType = function(mediaType) { - return "audio" === (mediaType = (mediaType || "").toLowerCase()) || "video" === mediaType - }, SessionPlayer.prototype.canQueueMediaType = function(mediaType) { - return this.canPlayMediaType(mediaType) - }, SessionPlayer.prototype.stop = function() { - sendPlayStateCommand(getCurrentApiClient(this), "stop") - }, SessionPlayer.prototype.nextTrack = function() { - sendPlayStateCommand(getCurrentApiClient(this), "nextTrack") - }, SessionPlayer.prototype.previousTrack = function() { - sendPlayStateCommand(getCurrentApiClient(this), "previousTrack") - }, SessionPlayer.prototype.seek = function(positionTicks) { - sendPlayStateCommand(getCurrentApiClient(this), "seek", { - SeekPositionTicks: positionTicks - }) - }, SessionPlayer.prototype.currentTime = function(val) { - if (null != val) return this.seek(val); + + var apiClient = getCurrentApiClient(this); + apiClient.sendCommand(sessionId, command); + }; + + SessionPlayer.prototype.play = function (options) { + + options = Object.assign({}, options); + + if (options.items) { + options.ids = options.items.map(function (i) { + return i.Id; + }); + + options.items = null; + } + + return sendPlayCommand(getCurrentApiClient(this), options, 'PlayNow'); + }; + + SessionPlayer.prototype.shuffle = function (item) { + + sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayShuffle'); + }; + + SessionPlayer.prototype.instantMix = function (item) { + + sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayInstantMix'); + }; + + SessionPlayer.prototype.queue = function (options) { + + sendPlayCommand(getCurrentApiClient(this), options, 'PlayNext'); + }; + + SessionPlayer.prototype.queueNext = function (options) { + + sendPlayCommand(getCurrentApiClient(this), options, 'PlayLast'); + }; + + SessionPlayer.prototype.canPlayMediaType = function (mediaType) { + + mediaType = (mediaType || '').toLowerCase(); + return mediaType === 'audio' || mediaType === 'video'; + }; + + SessionPlayer.prototype.canQueueMediaType = function (mediaType) { + return this.canPlayMediaType(mediaType); + }; + + SessionPlayer.prototype.stop = function () { + sendPlayStateCommand(getCurrentApiClient(this), 'stop'); + }; + + SessionPlayer.prototype.nextTrack = function () { + sendPlayStateCommand(getCurrentApiClient(this), 'nextTrack'); + }; + + SessionPlayer.prototype.previousTrack = function () { + sendPlayStateCommand(getCurrentApiClient(this), 'previousTrack'); + }; + + SessionPlayer.prototype.seek = function (positionTicks) { + sendPlayStateCommand(getCurrentApiClient(this), 'seek', + { + SeekPositionTicks: positionTicks + }); + }; + + SessionPlayer.prototype.currentTime = function (val) { + + if (val != null) { + return this.seek(val); + } + var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.PositionTicks - }, SessionPlayer.prototype.duration = function() { + state = state.PlayState || {}; + return state.PositionTicks; + }; + + SessionPlayer.prototype.duration = function () { var state = this.lastPlayerData || {}; - return state = state.NowPlayingItem || {}, state.RunTimeTicks - }, SessionPlayer.prototype.paused = function() { + state = state.NowPlayingItem || {}; + return state.RunTimeTicks; + }; + + SessionPlayer.prototype.paused = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.IsPaused - }, SessionPlayer.prototype.getVolume = function() { + state = state.PlayState || {}; + return state.IsPaused; + }; + + SessionPlayer.prototype.getVolume = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.VolumeLevel - }, SessionPlayer.prototype.isMuted = function() { + state = state.PlayState || {}; + return state.VolumeLevel; + }; + + SessionPlayer.prototype.isMuted = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.IsMuted - }, SessionPlayer.prototype.pause = function() { - sendPlayStateCommand(getCurrentApiClient(this), "Pause") - }, SessionPlayer.prototype.unpause = function() { - sendPlayStateCommand(getCurrentApiClient(this), "Unpause") - }, SessionPlayer.prototype.playPause = function() { - sendPlayStateCommand(getCurrentApiClient(this), "PlayPause") - }, SessionPlayer.prototype.setMute = function(isMuted) { - isMuted ? sendCommandByName(this, "Mute") : sendCommandByName(this, "Unmute") - }, SessionPlayer.prototype.toggleMute = function() { - sendCommandByName(this, "ToggleMute") - }, SessionPlayer.prototype.setVolume = function(vol) { - sendCommandByName(this, "SetVolume", { + state = state.PlayState || {}; + return state.IsMuted; + }; + + SessionPlayer.prototype.pause = function () { + sendPlayStateCommand(getCurrentApiClient(this), 'Pause'); + }; + + SessionPlayer.prototype.unpause = function () { + sendPlayStateCommand(getCurrentApiClient(this), 'Unpause'); + }; + + SessionPlayer.prototype.playPause = function () { + sendPlayStateCommand(getCurrentApiClient(this), 'PlayPause'); + }; + + SessionPlayer.prototype.setMute = function (isMuted) { + + if (isMuted) { + sendCommandByName(this, 'Mute'); + } else { + sendCommandByName(this, 'Unmute'); + } + }; + + SessionPlayer.prototype.toggleMute = function () { + sendCommandByName(this, 'ToggleMute'); + }; + + SessionPlayer.prototype.setVolume = function (vol) { + sendCommandByName(this, 'SetVolume', { Volume: vol - }) - }, SessionPlayer.prototype.volumeUp = function() { - sendCommandByName(this, "VolumeUp") - }, SessionPlayer.prototype.volumeDown = function() { - sendCommandByName(this, "VolumeDown") - }, SessionPlayer.prototype.toggleFullscreen = function() { - sendCommandByName(this, "ToggleFullscreen") - }, SessionPlayer.prototype.audioTracks = function() { + }); + }; + + SessionPlayer.prototype.volumeUp = function () { + sendCommandByName(this, 'VolumeUp'); + }; + + SessionPlayer.prototype.volumeDown = function () { + sendCommandByName(this, 'VolumeDown'); + }; + + SessionPlayer.prototype.toggleFullscreen = function () { + sendCommandByName(this, 'ToggleFullscreen'); + }; + + SessionPlayer.prototype.audioTracks = function () { var state = this.lastPlayerData || {}; - return state = state.NowPlayingItem || {}, (state.MediaStreams || []).filter(function(s) { - return "Audio" === s.Type - }) - }, SessionPlayer.prototype.getAudioStreamIndex = function() { + state = state.NowPlayingItem || {}; + var streams = state.MediaStreams || []; + return streams.filter(function (s) { + return s.Type === 'Audio'; + }); + }; + + SessionPlayer.prototype.getAudioStreamIndex = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.AudioStreamIndex - }, SessionPlayer.prototype.playTrailers = function(item) { - sendCommandByName(this, "PlayTrailers", { + state = state.PlayState || {}; + return state.AudioStreamIndex; + }; + + SessionPlayer.prototype.playTrailers = function (item) { + sendCommandByName(this, 'PlayTrailers', { ItemId: item.Id - }) - }, SessionPlayer.prototype.setAudioStreamIndex = function(index) { - sendCommandByName(this, "SetAudioStreamIndex", { + }); + }; + + SessionPlayer.prototype.setAudioStreamIndex = function (index) { + sendCommandByName(this, 'SetAudioStreamIndex', { Index: index - }) - }, SessionPlayer.prototype.subtitleTracks = function() { + }); + }; + + SessionPlayer.prototype.subtitleTracks = function () { var state = this.lastPlayerData || {}; - return state = state.NowPlayingItem || {}, (state.MediaStreams || []).filter(function(s) { - return "Subtitle" === s.Type - }) - }, SessionPlayer.prototype.getSubtitleStreamIndex = function() { + state = state.NowPlayingItem || {}; + var streams = state.MediaStreams || []; + return streams.filter(function (s) { + return s.Type === 'Subtitle'; + }); + }; + + SessionPlayer.prototype.getSubtitleStreamIndex = function () { var state = this.lastPlayerData || {}; - return state = state.PlayState || {}, state.SubtitleStreamIndex - }, SessionPlayer.prototype.setSubtitleStreamIndex = function(index) { - sendCommandByName(this, "SetSubtitleStreamIndex", { + state = state.PlayState || {}; + return state.SubtitleStreamIndex; + }; + + SessionPlayer.prototype.setSubtitleStreamIndex = function (index) { + sendCommandByName(this, 'SetSubtitleStreamIndex', { Index: index - }) - }, SessionPlayer.prototype.getMaxStreamingBitrate = function() {}, SessionPlayer.prototype.setMaxStreamingBitrate = function(options) {}, SessionPlayer.prototype.isFullscreen = function() {}, SessionPlayer.prototype.toggleFullscreen = function() {}, SessionPlayer.prototype.getRepeatMode = function() {}, SessionPlayer.prototype.setRepeatMode = function(mode) { - sendCommandByName(this, "SetRepeatMode", { + }); + }; + + SessionPlayer.prototype.getMaxStreamingBitrate = function () { + + }; + + SessionPlayer.prototype.setMaxStreamingBitrate = function (options) { + + }; + + SessionPlayer.prototype.isFullscreen = function () { + + }; + + SessionPlayer.prototype.toggleFullscreen = function () { + + }; + + SessionPlayer.prototype.getRepeatMode = function () { + + }; + + SessionPlayer.prototype.setRepeatMode = function (mode) { + + sendCommandByName(this, 'SetRepeatMode', { RepeatMode: mode - }) - }, SessionPlayer.prototype.displayContent = function(options) { - sendCommandByName(this, "DisplayContent", options) - }, SessionPlayer.prototype.isPlaying = function() { - return null != (this.lastPlayerData || {}).NowPlayingItem - }, SessionPlayer.prototype.isPlayingVideo = function() { + }); + }; + + SessionPlayer.prototype.displayContent = function (options) { + + sendCommandByName(this, 'DisplayContent', options); + }; + + SessionPlayer.prototype.isPlaying = function () { var state = this.lastPlayerData || {}; - return state = state.NowPlayingItem || {}, "Video" === state.MediaType - }, SessionPlayer.prototype.isPlayingAudio = function() { + return state.NowPlayingItem != null; + }; + + SessionPlayer.prototype.isPlayingVideo = function () { var state = this.lastPlayerData || {}; - return state = state.NowPlayingItem || {}, "Audio" === state.MediaType - }, SessionPlayer.prototype.getPlaylist = function() { - return Promise.resolve([]) - }, SessionPlayer.prototype.getCurrentPlaylistItemId = function() {}, SessionPlayer.prototype.setCurrentPlaylistItem = function(playlistItemId) { - return Promise.resolve() - }, SessionPlayer.prototype.removeFromPlaylist = function(playlistItemIds) { - return Promise.resolve() - }, SessionPlayer.prototype.tryPair = function(target) { - return Promise.resolve() - }, SessionPlayer + state = state.NowPlayingItem || {}; + return state.MediaType === 'Video'; + }; + + SessionPlayer.prototype.isPlayingAudio = function () { + var state = this.lastPlayerData || {}; + state = state.NowPlayingItem || {}; + return state.MediaType === 'Audio'; + }; + + SessionPlayer.prototype.getPlaylist = function () { + return Promise.resolve([]); + }; + + SessionPlayer.prototype.getCurrentPlaylistItemId = function () { + }; + + SessionPlayer.prototype.setCurrentPlaylistItem = function (playlistItemId) { + return Promise.resolve(); + }; + + SessionPlayer.prototype.removeFromPlaylist = function (playlistItemIds) { + return Promise.resolve(); + }; + + SessionPlayer.prototype.tryPair = function (target) { + + return Promise.resolve(); + }; + + return SessionPlayer; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/shell.js b/src/bower_components/emby-webcomponents/shell.js index 4c07437286..182178359c 100644 --- a/src/bower_components/emby-webcomponents/shell.js +++ b/src/bower_components/emby-webcomponents/shell.js @@ -1,12 +1,15 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; + return { - openUrl: function(url) { - window.open(url, "_blank") + openUrl: function (url) { + window.open(url, '_blank'); }, - canExec: !1, - exec: function(options) { - return Promise.reject() + canExec: false, + exec: function (options) { + // options.path + // options.arguments + return Promise.reject(); } - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/shortcuts.js b/src/bower_components/emby-webcomponents/shortcuts.js index f14e219fe7..f446bd216c 100644 --- a/src/bower_components/emby-webcomponents/shortcuts.js +++ b/src/bower_components/emby-webcomponents/shortcuts.js @@ -1,248 +1,457 @@ -define(["playbackManager", "inputManager", "connectionManager", "appRouter", "globalize", "loading", "dom", "recordingHelper"], function(playbackManager, inputManager, connectionManager, appRouter, globalize, loading, dom, recordingHelper) { - "use strict"; +define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'globalize', 'loading', 'dom', 'recordingHelper'], function (playbackManager, inputManager, connectionManager, appRouter, globalize, loading, dom, recordingHelper) { + 'use strict'; function playAllFromHere(card, serverId, queue) { - for (var startIndex, parent = card.parentNode, className = card.classList.length ? "." + card.classList[0] : "", cards = parent.querySelectorAll(className + "[data-id]"), ids = [], foundCard = !1, i = 0, length = cards.length; i < length; i++) cards[i] === card && (foundCard = !0, startIndex = i), !foundCard && queue || ids.push(cards[i].getAttribute("data-id")); - var itemsContainer = dom.parentWithClass(card, "itemsContainer"); - if (itemsContainer && itemsContainer.fetchData) { - var queryOptions = queue ? { - StartIndex: startIndex - } : {}; - return itemsContainer.fetchData(queryOptions).then(function(result) { - return queue ? playbackManager.queue({ - items: result.Items - }) : playbackManager.play({ - items: result.Items, - startIndex: startIndex - }) - }) + + var parent = card.parentNode; + var className = card.classList.length ? ('.' + card.classList[0]) : ''; + var cards = parent.querySelectorAll(className + '[data-id]'); + + var ids = []; + + var foundCard = false; + var startIndex; + + for (var i = 0, length = cards.length; i < length; i++) { + if (cards[i] === card) { + foundCard = true; + startIndex = i; + } + if (foundCard || !queue) { + ids.push(cards[i].getAttribute('data-id')); + } + } + + var itemsContainer = dom.parentWithClass(card, 'itemsContainer'); + if (itemsContainer && itemsContainer.fetchData) { + + var queryOptions = queue ? { StartIndex: startIndex } : {}; + + return itemsContainer.fetchData(queryOptions).then(function (result) { + + if (queue) { + return playbackManager.queue({ + items: result.Items + }); + } else { + + return playbackManager.play({ + items: result.Items, + startIndex: startIndex + }); + } + }); + } + + if (!ids.length) { + return; + } + + if (queue) { + return playbackManager.queue({ + ids: ids, + serverId: serverId + }); + } else { + + return playbackManager.play({ + ids: ids, + serverId: serverId, + startIndex: startIndex + }); } - if (ids.length) return queue ? playbackManager.queue({ - ids: ids, - serverId: serverId - }) : playbackManager.play({ - ids: ids, - serverId: serverId, - startIndex: startIndex - }) } function showProgramDialog(item) { - require(["recordingCreator"], function(recordingCreator) { - recordingCreator.show(item.Id, item.ServerId) - }) + + require(['recordingCreator'], function (recordingCreator) { + + recordingCreator.show(item.Id, item.ServerId); + }); } function getItem(button) { - button = dom.parentWithAttribute(button, "data-id"); - var serverId = button.getAttribute("data-serverid"), - id = button.getAttribute("data-id"), - type = button.getAttribute("data-type"), - apiClient = connectionManager.getApiClient(serverId); - return "Timer" === type ? apiClient.getLiveTvTimer(id) : "SeriesTimer" === type ? apiClient.getLiveTvSeriesTimer(id) : apiClient.getItem(apiClient.getCurrentUserId(), id) + + button = dom.parentWithAttribute(button, 'data-id'); + var serverId = button.getAttribute('data-serverid'); + var id = button.getAttribute('data-id'); + var type = button.getAttribute('data-type'); + + var apiClient = connectionManager.getApiClient(serverId); + + if (type === 'Timer') { + return apiClient.getLiveTvTimer(id); + } + if (type === 'SeriesTimer') { + return apiClient.getLiveTvSeriesTimer(id); + } + return apiClient.getItem(apiClient.getCurrentUserId(), id); } function notifyRefreshNeeded(childElement, itemsContainer) { - (itemsContainer = itemsContainer || dom.parentWithAttribute(childElement, "is", "emby-itemscontainer")) && itemsContainer.notifyRefreshNeeded(!0) + + itemsContainer = itemsContainer || dom.parentWithAttribute(childElement, 'is', 'emby-itemscontainer'); + + if (itemsContainer) { + itemsContainer.notifyRefreshNeeded(true); + } } function showContextMenu(card, options) { - getItem(card).then(function(item) { - var playlistId = card.getAttribute("data-playlistid"), - collectionId = card.getAttribute("data-collectionid"); + + getItem(card).then(function (item) { + + var playlistId = card.getAttribute('data-playlistid'); + var collectionId = card.getAttribute('data-collectionid'); + if (playlistId) { - var elem = dom.parentWithAttribute(card, "data-playlistitemid"); - item.PlaylistItemId = elem ? elem.getAttribute("data-playlistitemid") : null + var elem = dom.parentWithAttribute(card, 'data-playlistitemid'); + item.PlaylistItemId = elem ? elem.getAttribute('data-playlistitemid') : null; } - require(["itemContextMenu"], function(itemContextMenu) { - connectionManager.getApiClient(item.ServerId).getCurrentUser().then(function(user) { + + require(['itemContextMenu'], function (itemContextMenu) { + + connectionManager.getApiClient(item.ServerId).getCurrentUser().then(function (user) { itemContextMenu.show(Object.assign({ item: item, - play: !0, - queue: !0, + play: true, + queue: true, playAllFromHere: !item.IsFolder, queueAllFromHere: !item.IsFolder, playlistId: playlistId, collectionId: collectionId, user: user - }, options || {})).then(function(result) { - "playallfromhere" === result.command || "queueallfromhere" === result.command ? executeAction(card, options.positionTo, result.command) : (result.updated || result.deleted) && notifyRefreshNeeded(card, options.itemsContainer) - }) - }) - }) - }) + + }, options || {})).then(function (result) { + + var itemsContainer; + + if (result.command === 'playallfromhere' || result.command === 'queueallfromhere') { + executeAction(card, options.positionTo, result.command); + } + else if (result.updated || result.deleted) { + notifyRefreshNeeded(card, options.itemsContainer); + } + }); + }); + }); + }); } function getItemInfoFromCard(card) { + return { - Type: card.getAttribute("data-type"), - Id: card.getAttribute("data-id"), - TimerId: card.getAttribute("data-timerid"), - CollectionType: card.getAttribute("data-collectiontype"), - ChannelId: card.getAttribute("data-channelid"), - SeriesId: card.getAttribute("data-seriesid"), - ServerId: card.getAttribute("data-serverid"), - MediaType: card.getAttribute("data-mediatype"), - IsFolder: "true" === card.getAttribute("data-isfolder"), + Type: card.getAttribute('data-type'), + Id: card.getAttribute('data-id'), + TimerId: card.getAttribute('data-timerid'), + CollectionType: card.getAttribute('data-collectiontype'), + ChannelId: card.getAttribute('data-channelid'), + SeriesId: card.getAttribute('data-seriesid'), + ServerId: card.getAttribute('data-serverid'), + MediaType: card.getAttribute('data-mediatype'), + IsFolder: card.getAttribute('data-isfolder') === 'true', UserData: { - PlaybackPositionTicks: parseInt(card.getAttribute("data-positionticks") || "0") + PlaybackPositionTicks: parseInt(card.getAttribute('data-positionticks') || '0') } - } + }; } function showPlayMenu(card, target) { + var item = getItemInfoFromCard(card); - require(["playMenu"], function(playMenu) { + + require(['playMenu'], function (playMenu) { + playMenu.show({ + item: item, positionTo: target - }) - }) + }); + }); } function sendToast(text) { - require(["toast"], function(toast) { - toast(text) - }) + require(['toast'], function (toast) { + toast(text); + }); } function executeAction(card, target, action) { + target = target || card; - var id = card.getAttribute("data-id"); - id || (card = dom.parentWithAttribute(card, "data-id"), id = card.getAttribute("data-id")); - var item = getItemInfoFromCard(card), - serverId = item.ServerId, - type = item.Type, - playableItemId = "Program" === type ? item.ChannelId : item.Id; - if ("Photo" === item.MediaType && "link" === action && (action = "play"), "link" === action) appRouter.showItem(item, { - context: card.getAttribute("data-context"), - parentId: card.getAttribute("data-parentid") - }); - else if ("programdialog" === action) showProgramDialog(item); - else if ("instantmix" === action) playbackManager.instantMix({ - Id: playableItemId, - ServerId: serverId - }); - else if ("play" === action || "resume" === action) { - var startPositionTicks = parseInt(card.getAttribute("data-positionticks") || "0"); + + var id = card.getAttribute('data-id'); + + if (!id) { + card = dom.parentWithAttribute(card, 'data-id'); + id = card.getAttribute('data-id'); + } + + var item = getItemInfoFromCard(card); + + var serverId = item.ServerId; + var type = item.Type; + + var playableItemId = type === 'Program' ? item.ChannelId : item.Id; + + if (item.MediaType === 'Photo' && action === 'link') { + action = 'play'; + } + + if (action === 'link') { + + appRouter.showItem(item, { + context: card.getAttribute('data-context'), + parentId: card.getAttribute('data-parentid') + }); + } + + else if (action === 'programdialog') { + + showProgramDialog(item); + } + + else if (action === 'instantmix') { + playbackManager.instantMix({ + Id: playableItemId, + ServerId: serverId + }); + } + + else if (action === 'play' || action === 'resume') { + + var startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0'); + playbackManager.play({ ids: [playableItemId], startPositionTicks: startPositionTicks, serverId: serverId - }) - } else if ("queue" === action) playbackManager.isPlaying() ? (playbackManager.queue({ - ids: [playableItemId], - serverId: serverId - }), sendToast(globalize.translate("sharedcomponents#MediaQueued"))) : playbackManager.queue({ - ids: [playableItemId], - serverId: serverId - }); - else if ("playallfromhere" === action) playAllFromHere(card, serverId); - else if ("queueallfromhere" === action) playAllFromHere(card, serverId, !0); - else if ("setplaylistindex" === action) playbackManager.setCurrentPlaylistItem(card.getAttribute("data-playlistitemid")); - else if ("record" === action) onRecordCommand(serverId, id, type, card.getAttribute("data-timerid"), card.getAttribute("data-seriestimerid")); - else if ("menu" === action) { - var options = "false" === target.getAttribute("data-playoptions") ? { - shuffle: !1, - instantMix: !1, - play: !1, - playAllFromHere: !1, - queue: !1, - queueAllFromHere: !1 - } : {}; - options.positionTo = target, showContextMenu(card, options) - } else if ("playmenu" === action) showPlayMenu(card, target); - else if ("edit" === action) getItem(target).then(function(item) { - editItem(item, serverId) - }); - else if ("playtrailer" === action) getItem(target).then(playTrailer); - else if ("addtoplaylist" === action) getItem(target).then(addToPlaylist); - else if ("custom" === action) { - var customAction = target.getAttribute("data-customaction"); - card.dispatchEvent(new CustomEvent("action-" + customAction, { + }); + } + + else if (action === 'queue') { + + if (playbackManager.isPlaying()) { + playbackManager.queue({ + ids: [playableItemId], + serverId: serverId + }); + sendToast(globalize.translate('sharedcomponents#MediaQueued')); + } else { + playbackManager.queue({ + ids: [playableItemId], + serverId: serverId + }); + } + } + + else if (action === 'playallfromhere') { + playAllFromHere(card, serverId); + } + + else if (action === 'queueallfromhere') { + playAllFromHere(card, serverId, true); + } + + else if (action === 'setplaylistindex') { + playbackManager.setCurrentPlaylistItem(card.getAttribute('data-playlistitemid')); + } + + else if (action === 'record') { + onRecordCommand(serverId, id, type, card.getAttribute('data-timerid'), card.getAttribute('data-seriestimerid')); + } + + else if (action === 'menu') { + + var options = target.getAttribute('data-playoptions') === 'false' ? + { + shuffle: false, + instantMix: false, + play: false, + playAllFromHere: false, + queue: false, + queueAllFromHere: false + } : + {}; + + options.positionTo = target; + + showContextMenu(card, options); + } + + else if (action === 'playmenu') { + showPlayMenu(card, target); + } + + else if (action === 'edit') { + getItem(target).then(function (item) { + editItem(item, serverId); + }); + } + + else if (action === 'playtrailer') { + getItem(target).then(playTrailer); + } + + else if (action === 'addtoplaylist') { + getItem(target).then(addToPlaylist); + } + + else if (action === 'custom') { + + var customAction = target.getAttribute('data-customaction'); + + card.dispatchEvent(new CustomEvent('action-' + customAction, { detail: { - playlistItemId: card.getAttribute("data-playlistitemid") + playlistItemId: card.getAttribute('data-playlistitemid') }, - cancelable: !1, - bubbles: !0 - })) + cancelable: false, + bubbles: true + })); } } function addToPlaylist(item) { - require(["playlistEditor"], function(playlistEditor) { - (new playlistEditor).show({ + require(['playlistEditor'], function (playlistEditor) { + + new playlistEditor().show({ items: [item.Id], serverId: item.ServerId - }) - }) + + }); + }); } function playTrailer(item) { + var apiClient = connectionManager.getApiClient(item.ServerId); - apiClient.getLocalTrailers(apiClient.getCurrentUserId(), item.Id).then(function(trailers) { - playbackManager.play({ - items: trailers - }) - }) + + apiClient.getLocalTrailers(apiClient.getCurrentUserId(), item.Id).then(function (trailers) { + playbackManager.play({ items: trailers }); + }); } function editItem(item, serverId) { + var apiClient = connectionManager.getApiClient(serverId); - return new Promise(function(resolve, reject) { + + return new Promise(function (resolve, reject) { + var serverId = apiClient.serverInfo().Id; - "Timer" === item.Type ? item.ProgramId ? require(["recordingCreator"], function(recordingCreator) { - recordingCreator.show(item.ProgramId, serverId).then(resolve, reject) - }) : require(["recordingEditor"], function(recordingEditor) { - recordingEditor.show(item.Id, serverId).then(resolve, reject) - }) : require(["metadataEditor"], function(metadataEditor) { - metadataEditor.show(item.Id, serverId).then(resolve, reject) - }) - }) + + if (item.Type === 'Timer') { + if (item.ProgramId) { + require(['recordingCreator'], function (recordingCreator) { + + recordingCreator.show(item.ProgramId, serverId).then(resolve, reject); + }); + } else { + require(['recordingEditor'], function (recordingEditor) { + + recordingEditor.show(item.Id, serverId).then(resolve, reject); + }); + } + } else { + require(['metadataEditor'], function (metadataEditor) { + + metadataEditor.show(item.Id, serverId).then(resolve, reject); + }); + } + }); } function onRecordCommand(serverId, id, type, timerId, seriesTimerId) { - if ("Program" === type || timerId || seriesTimerId) { - var programId = "Program" === type ? id : null; - recordingHelper.toggleRecording(serverId, programId, timerId, seriesTimerId) + + if (type === 'Program' || timerId || seriesTimerId) { + + var programId = type === 'Program' ? id : null; + recordingHelper.toggleRecording(serverId, programId, timerId, seriesTimerId); } } function onClick(e) { - var card = dom.parentWithClass(e.target, "itemAction"); + + var card = dom.parentWithClass(e.target, 'itemAction'); + if (card) { - var actionElement = card, - action = actionElement.getAttribute("data-action"); - if (action || (actionElement = dom.parentWithAttribute(actionElement, "data-action")) && (action = actionElement.getAttribute("data-action")), action) return executeAction(card, actionElement, action), e.preventDefault(), e.stopPropagation(), !1 + + var actionElement = card; + var action = actionElement.getAttribute('data-action'); + + if (!action) { + actionElement = dom.parentWithAttribute(actionElement, 'data-action'); + if (actionElement) { + action = actionElement.getAttribute('data-action'); + } + } + + if (action) { + executeAction(card, actionElement, action); + + e.preventDefault(); + e.stopPropagation(); + return false; + } } } function onCommand(e) { + var cmd = e.detail.command; - if ("play" === cmd || "resume" === cmd || "record" === cmd || "menu" === cmd || "info" === cmd) { - var target = e.target, - card = dom.parentWithClass(target, "itemAction") || dom.parentWithAttribute(target, "data-id"); - card && (e.preventDefault(), e.stopPropagation(), executeAction(card, card, cmd)) + + if (cmd === 'play' || cmd === 'resume' || cmd === 'record' || cmd === 'menu' || cmd === 'info') { + + var target = e.target; + var card = dom.parentWithClass(target, 'itemAction') || dom.parentWithAttribute(target, 'data-id'); + + if (card) { + e.preventDefault(); + e.stopPropagation(); + executeAction(card, card, cmd); + } } } function on(context, options) { - options = options || {}, !1 !== options.click && context.addEventListener("click", onClick), !1 !== options.command && inputManager.on(context, onCommand) + + options = options || {}; + + if (options.click !== false) { + context.addEventListener('click', onClick); + } + + if (options.command !== false) { + inputManager.on(context, onCommand); + } } function off(context, options) { - options = options || {}, context.removeEventListener("click", onClick), !1 !== options.command && inputManager.off(context, onCommand) + options = options || {}; + + context.removeEventListener('click', onClick); + + if (options.command !== false) { + inputManager.off(context, onCommand); + } } function getShortcutAttributesHtml(item, serverId) { - var html = 'data-id="' + item.Id + '" data-serverid="' + (serverId || item.ServerId) + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-channelid="' + item.ChannelId + '" data-isfolder="' + item.IsFolder + '"', - collectionType = item.CollectionType; - return collectionType && (html += ' data-collectiontype="' + collectionType + '"'), html + + var html = 'data-id="' + item.Id + '" data-serverid="' + (serverId || item.ServerId) + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-channelid="' + item.ChannelId + '" data-isfolder="' + item.IsFolder + '"'; + + var collectionType = item.CollectionType; + if (collectionType) { + html += ' data-collectiontype="' + collectionType + '"'; + } + + return html; } + return { on: on, off: off, onClick: onClick, getShortcutAttributesHtml: getShortcutAttributesHtml - } + }; + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/skinmanager.js b/src/bower_components/emby-webcomponents/skinmanager.js index 962b3319af..67b4e63c2d 100644 --- a/src/bower_components/emby-webcomponents/skinmanager.js +++ b/src/bower_components/emby-webcomponents/skinmanager.js @@ -1,186 +1,393 @@ -define(["apphost", "userSettings", "browser", "events", "pluginManager", "backdrop", "globalize", "require", "appSettings"], function(appHost, userSettings, browser, events, pluginManager, backdrop, globalize, require, appSettings) { - "use strict"; +define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdrop', 'globalize', 'require', 'appSettings'], function (appHost, userSettings, browser, events, pluginManager, backdrop, globalize, require, appSettings) { + 'use strict'; + + var currentSkin; function getCurrentSkin() { - return currentSkin + return currentSkin; } function getRequirePromise(deps) { - return new Promise(function(resolve, reject) { - require(deps, resolve) - }) + return new Promise(function (resolve, reject) { + + require(deps, resolve); + }); } function loadSkin(id) { - var newSkin = pluginManager.plugins().filter(function(p) { - return p.id === id + + var newSkin = pluginManager.plugins().filter(function (p) { + return p.id === id; })[0]; - newSkin || (newSkin = pluginManager.plugins().filter(function(p) { - return "defaultskin" === p.id - })[0]); + + if (!newSkin) { + newSkin = pluginManager.plugins().filter(function (p) { + return p.id === 'defaultskin'; + })[0]; + } + var unloadPromise; + if (currentSkin) { - if (currentSkin.id === newSkin.id) return Promise.resolve(currentSkin); - unloadPromise = unloadSkin(currentSkin) - } else unloadPromise = Promise.resolve(); - return unloadPromise.then(function() { + + if (currentSkin.id === newSkin.id) { + // Nothing to do, it's already the active skin + return Promise.resolve(currentSkin); + } + unloadPromise = unloadSkin(currentSkin); + } else { + unloadPromise = Promise.resolve(); + } + + return unloadPromise.then(function () { var deps = newSkin.getDependencies(); - return console.log("Loading skin dependencies"), getRequirePromise(deps).then(function() { - console.log("Skin dependencies loaded"); + + console.log('Loading skin dependencies'); + + return getRequirePromise(deps).then(function () { + + console.log('Skin dependencies loaded'); + var strings = newSkin.getTranslations ? newSkin.getTranslations() : []; + return globalize.loadStrings({ + name: newSkin.id, strings: strings - }).then(function() { - return globalize.defaultModule(newSkin.id), loadSkinHeader(newSkin) - }) - }) - }) + + }).then(function () { + + globalize.defaultModule(newSkin.id); + return loadSkinHeader(newSkin); + }); + }); + }); } function unloadSkin(skin) { - return unloadTheme(), backdrop.clear(), console.log("Unloading skin: " + skin.name), skin.unload().then(function() { + + unloadTheme(); + backdrop.clear(); + + console.log('Unloading skin: ' + skin.name); + + // TODO: unload css + + return skin.unload().then(function () { document.dispatchEvent(new CustomEvent("skinunload", { detail: { name: skin.name } - })) - }) + })); + }); } function loadSkinHeader(skin) { - return getSkinHeader(skin).then(function(headerHtml) { - return document.querySelector(".skinHeader").innerHTML = headerHtml, currentSkin = skin, skin.load(), skin - }) + + return getSkinHeader(skin).then(function (headerHtml) { + + document.querySelector('.skinHeader').innerHTML = headerHtml; + + currentSkin = skin; + skin.load(); + + return skin; + }); } + var cacheParam = new Date().getTime(); + function getSkinHeader(skin) { - return new Promise(function(resolve, reject) { - if (!skin.getHeaderTemplate) return void resolve(""); - var xhr = new XMLHttpRequest, - url = skin.getHeaderTemplate(); - url += -1 === url.indexOf("?") ? "?" : "&", url += "v=" + cacheParam, xhr.open("GET", url, !0), xhr.onload = function(e) { - resolve(this.status < 400 ? this.response : "") - }, xhr.send() - }) + + return new Promise(function (resolve, reject) { + + if (!skin.getHeaderTemplate) { + resolve(''); + return; + } + + var xhr = new XMLHttpRequest(); + + var url = skin.getHeaderTemplate(); + url += url.indexOf('?') === -1 ? '?' : '&'; + url += 'v=' + cacheParam; + + xhr.open('GET', url, true); + + xhr.onload = function (e) { + if (this.status < 400) { + resolve(this.response); + } else { + resolve(''); + } + }; + + xhr.send(); + }); } function loadUserSkin(options) { - loadSkin(userSettings.get("skin", !1) || "defaultskin").then(function(skin) { - options = options || {}, options.start ? Emby.Page.invokeShortcut(options.start) : Emby.Page.goHome() - }) + + var skin = userSettings.get('skin', false) || 'defaultskin'; + + loadSkin(skin).then(function (skin) { + + options = options || {}; + if (options.start) { + Emby.Page.invokeShortcut(options.start); + } else { + Emby.Page.goHome(); + } + }); } + events.on(userSettings, 'change', function (e, name) { + if (name === 'skin' || name === 'language') { + loadUserSkin(); + } + }); + + var themeStyleElement; + var currentThemeId; function unloadTheme() { var elem = themeStyleElement; - elem && (elem.parentNode.removeChild(elem), themeStyleElement = null, currentThemeId = null) + if (elem) { + + elem.parentNode.removeChild(elem); + themeStyleElement = null; + currentThemeId = null; + } } function getThemes() { - return currentSkin.getThemes ? currentSkin.getThemes() : [] + + if (currentSkin.getThemes) { + return currentSkin.getThemes(); + } + + return []; } + var skinManager = { + getCurrentSkin: getCurrentSkin, + loadSkin: loadSkin, + loadUserSkin: loadUserSkin, + getThemes: getThemes + }; + function onRegistrationSuccess() { - appSettings.set("appthemesregistered", "true") + appSettings.set('appthemesregistered', 'true'); } function onRegistrationFailure() { - appSettings.set("appthemesregistered", "false") + appSettings.set('appthemesregistered', 'false'); } function isRegistered() { - return getRequirePromise(["registrationServices"]).then(function(registrationServices) { - registrationServices.validateFeature("themes", { - showDialog: !1 - }).then(onRegistrationSuccess, onRegistrationFailure) - }), "false" !== appSettings.get("appthemesregistered") + + getRequirePromise(['registrationServices']).then(function (registrationServices) { + registrationServices.validateFeature('themes', { + + showDialog: false + + }).then(onRegistrationSuccess, onRegistrationFailure); + }); + + return appSettings.get('appthemesregistered') !== 'false'; } function getThemeStylesheetInfo(id, requiresRegistration, isDefaultProperty) { - for (var defaultTheme, selectedTheme, themes = skinManager.getThemes(), i = 0, length = themes.length; i < length; i++) { + + var themes = skinManager.getThemes(); + var defaultTheme; + var selectedTheme; + + for (var i = 0, length = themes.length; i < length; i++) { + var theme = themes[i]; - theme[isDefaultProperty] && (defaultTheme = theme), id === theme.id && (selectedTheme = theme) + if (theme[isDefaultProperty]) { + defaultTheme = theme; + } + if (id === theme.id) { + selectedTheme = theme; + } } - selectedTheme = selectedTheme || defaultTheme, selectedTheme.id !== defaultTheme.id && requiresRegistration && !isRegistered() && (selectedTheme = defaultTheme); + + selectedTheme = selectedTheme || defaultTheme; + + if (selectedTheme.id !== defaultTheme.id && requiresRegistration && !isRegistered()) { + selectedTheme = defaultTheme; + } + + var embyWebComponentsBowerPath = 'bower_components/emby-webcomponents'; + return { - stylesheetPath: require.toUrl("bower_components/emby-webcomponents/themes/" + selectedTheme.id + "/theme.css"), + stylesheetPath: require.toUrl(embyWebComponentsBowerPath + '/themes/' + selectedTheme.id + '/theme.css'), themeId: selectedTheme.id - } + }; } + var themeResources = {}; function modifyThemeForSeasonal(id) { - if (!userSettings.enableSeasonalThemes()) return id; - var date = new Date, - month = date.getMonth(), - day = date.getDate(); - return 9 === month && day >= 30 ? "halloween" : id + + if (!userSettings.enableSeasonalThemes()) { + return id; + } + + var date = new Date(); + var month = date.getMonth(); + var day = date.getDate(); + + if (month === 9 && day >= 30) { + return 'halloween'; + } + + return id; } + var lastSound = 0; + var currentSound; + function loadThemeResources(id) { - if (lastSound = 0, currentSound && (currentSound.stop(), currentSound = null), backdrop.clear(), "halloween" === id) return void(themeResources = { - themeSong: "https://github.com/MediaBrowser/Emby.Resources/raw/master/themes/halloween/monsterparadefade.mp3", - effect: "https://github.com/MediaBrowser/Emby.Resources/raw/master/themes/halloween/howl.wav", - backdrop: "https://github.com/MediaBrowser/Emby.Resources/raw/master/themes/halloween/bg.jpg" - }); - themeResources = {} + + lastSound = 0; + + if (currentSound) { + currentSound.stop(); + currentSound = null; + } + + backdrop.clear(); + + if (id === 'halloween') { + themeResources = { + themeSong: 'https://github.com/MediaBrowser/Emby.Resources/raw/master/themes/halloween/monsterparadefade.mp3', + effect: 'https://github.com/MediaBrowser/Emby.Resources/raw/master/themes/halloween/howl.wav', + backdrop: 'https://github.com/MediaBrowser/Emby.Resources/raw/master/themes/halloween/bg.jpg' + }; + return; + } + + themeResources = { + }; } function onThemeLoaded() { - document.documentElement.classList.remove("preload"); + document.documentElement.classList.remove('preload'); + + try { - var color = getComputedStyle(document.querySelector(".skinHeader")).getPropertyValue("background-color"); - color && appHost.setThemeColor(color) - } catch (err) { - console.log("Error setting theme color: " + err) + var color = getComputedStyle(document.querySelector('.skinHeader')).getPropertyValue("background-color"); + + if (color) { + appHost.setThemeColor(color); + } + } + catch (err) { + console.log('Error setting theme color: ' + err); } } + skinManager.setTheme = function (id, context) { + + return new Promise(function (resolve, reject) { + + var requiresRegistration = true; + + if (context !== 'serverdashboard') { + + var newId = modifyThemeForSeasonal(id); + if (newId !== id) { + requiresRegistration = false; + } + id = newId; + } + + if (currentThemeId && currentThemeId === id) { + resolve(); + return; + } + + var isDefaultProperty = context === 'serverdashboard' ? 'isDefaultServerDashboard' : 'isDefault'; + var info = getThemeStylesheetInfo(id, requiresRegistration, isDefaultProperty); + + if (currentThemeId && currentThemeId === info.themeId) { + resolve(); + return; + } + + var linkUrl = info.stylesheetPath; + + unloadTheme(); + + var link = document.createElement('link'); + + link.setAttribute('rel', 'stylesheet'); + link.setAttribute('type', 'text/css'); + link.onload = function () { + + onThemeLoaded(); + resolve(); + }; + + link.setAttribute('href', linkUrl); + document.head.appendChild(link); + themeStyleElement = link; + currentThemeId = info.themeId; + loadThemeResources(info.themeId); + + onViewBeforeShow({}); + }); + }; + function onViewBeforeShow(e) { - e.detail && "video-osd" === e.detail.type || (themeResources.backdrop && backdrop.setBackdrop(themeResources.backdrop), !browser.mobile && userSettings.enableThemeSongs() && (0 === lastSound ? themeResources.themeSong && playSound(themeResources.themeSong) : (new Date).getTime() - lastSound > 3e4 && themeResources.effect && playSound(themeResources.effect))) + + if (e.detail && e.detail.type === 'video-osd') { + return; + } + + if (themeResources.backdrop) { + + backdrop.setBackdrop(themeResources.backdrop); + } + + if (!browser.mobile && userSettings.enableThemeSongs()) { + if (lastSound === 0) { + + if (themeResources.themeSong) { + playSound(themeResources.themeSong); + } + + } else if ((new Date().getTime() - lastSound) > 30000) { + if (themeResources.effect) { + playSound(themeResources.effect); + } + } + } } + document.addEventListener('viewshow', onViewBeforeShow); + function playSound(path, volume) { - lastSound = (new Date).getTime(), require(["howler"], function(howler) { + + lastSound = new Date().getTime(); + + require(['howler'], function (howler) { + try { var sound = new Howl({ src: [path], - volume: volume || .1 + volume: volume || 0.1 }); - sound.play(), currentSound = sound - } catch (err) { - console.log("Error playing sound: " + err) + + sound.play(); + currentSound = sound; } - }) + catch (err) { + console.log('Error playing sound: ' + err); + } + }); } - var currentSkin, cacheParam = (new Date).getTime(); - events.on(userSettings, "change", function(e, name) { - "skin" !== name && "language" !== name || loadUserSkin() - }); - var themeStyleElement, currentThemeId, currentSound, skinManager = { - getCurrentSkin: getCurrentSkin, - loadSkin: loadSkin, - loadUserSkin: loadUserSkin, - getThemes: getThemes - }, - themeResources = {}, - lastSound = 0; - return skinManager.setTheme = function(id, context) { - return new Promise(function(resolve, reject) { - var requiresRegistration = !0; - if ("serverdashboard" !== context) { - var newId = modifyThemeForSeasonal(id); - newId !== id && (requiresRegistration = !1), id = newId - } - if (currentThemeId && currentThemeId === id) return void resolve(); - var isDefaultProperty = "serverdashboard" === context ? "isDefaultServerDashboard" : "isDefault", - info = getThemeStylesheetInfo(id, requiresRegistration, isDefaultProperty); - if (currentThemeId && currentThemeId === info.themeId) return void resolve(); - var linkUrl = info.stylesheetPath; - unloadTheme(); - var link = document.createElement("link"); - link.setAttribute("rel", "stylesheet"), link.setAttribute("type", "text/css"), link.onload = function() { - onThemeLoaded(), resolve() - }, link.setAttribute("href", linkUrl), document.head.appendChild(link), themeStyleElement = link, currentThemeId = info.themeId, loadThemeResources(info.themeId), onViewBeforeShow({}) - }) - }, document.addEventListener("viewshow", onViewBeforeShow), skinManager + + return skinManager; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/slideshow/slideshow.js b/src/bower_components/emby-webcomponents/slideshow/slideshow.js index c5aeffc832..42cdabfffd 100644 --- a/src/bower_components/emby-webcomponents/slideshow/slideshow.js +++ b/src/bower_components/emby-webcomponents/slideshow/slideshow.js @@ -1,317 +1,643 @@ -define(["dialogHelper", "inputManager", "connectionManager", "layoutManager", "focusManager", "browser", "apphost", "loading", "css!./style", "material-icons", "paper-icon-button-light"], function(dialogHelper, inputmanager, connectionManager, layoutManager, focusManager, browser, appHost, loading) { - "use strict"; +define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'focusManager', 'browser', 'apphost', 'loading', 'css!./style', 'material-icons', 'paper-icon-button-light'], function (dialogHelper, inputmanager, connectionManager, layoutManager, focusManager, browser, appHost, loading) { + 'use strict'; function getImageUrl(item, options, apiClient) { - return options = options || {}, options.type = options.type || "Primary", "string" == typeof item ? apiClient.getScaledImageUrl(item, options) : item.ImageTags && item.ImageTags[options.type] ? (options.tag = item.ImageTags[options.type], apiClient.getScaledImageUrl(item.Id, options)) : "Primary" === options.type && item.AlbumId && item.AlbumPrimaryImageTag ? (options.tag = item.AlbumPrimaryImageTag, apiClient.getScaledImageUrl(item.AlbumId, options)) : null + + options = options || {}; + options.type = options.type || "Primary"; + + if (typeof (item) === 'string') { + return apiClient.getScaledImageUrl(item, options); + } + + if (item.ImageTags && item.ImageTags[options.type]) { + + options.tag = item.ImageTags[options.type]; + return apiClient.getScaledImageUrl(item.Id, options); + } + + if (options.type === 'Primary') { + if (item.AlbumId && item.AlbumPrimaryImageTag) { + + options.tag = item.AlbumPrimaryImageTag; + return apiClient.getScaledImageUrl(item.AlbumId, options); + } + } + + return null; } function getBackdropImageUrl(item, options, apiClient) { - return options = options || {}, options.type = options.type || "Backdrop", options.maxWidth || options.width || options.maxHeight || options.height || (options.quality = 100), item.BackdropImageTags && item.BackdropImageTags.length ? (options.tag = item.BackdropImageTags[0], apiClient.getScaledImageUrl(item.Id, options)) : null + + options = options || {}; + options.type = options.type || "Backdrop"; + + // If not resizing, get the original image + if (!options.maxWidth && !options.width && !options.maxHeight && !options.height) { + options.quality = 100; + } + + if (item.BackdropImageTags && item.BackdropImageTags.length) { + + options.tag = item.BackdropImageTags[0]; + return apiClient.getScaledImageUrl(item.Id, options); + } + + return null; } function getImgUrl(item, original) { - var apiClient = connectionManager.getApiClient(item.ServerId), - imageOptions = {}; - return original || (imageOptions.maxWidth = screen.availWidth), item.BackdropImageTags && item.BackdropImageTags.length ? getBackdropImageUrl(item, imageOptions, apiClient) : "Photo" === item.MediaType && original ? apiClient.getItemDownloadUrl(item.Id) : (imageOptions.type = "Primary", getImageUrl(item, imageOptions, apiClient)) + + var apiClient = connectionManager.getApiClient(item.ServerId); + var imageOptions = {}; + + if (!original) { + imageOptions.maxWidth = screen.availWidth; + } + if (item.BackdropImageTags && item.BackdropImageTags.length) { + return getBackdropImageUrl(item, imageOptions, apiClient); + } else { + + if (item.MediaType === 'Photo' && original) { + return apiClient.getItemDownloadUrl(item.Id); + } + imageOptions.type = "Primary"; + return getImageUrl(item, imageOptions, apiClient); + } } function getIcon(icon, cssClass, canFocus, autoFocus) { - var tabIndex = canFocus ? "" : ' tabindex="-1"'; - return autoFocus = autoFocus ? " autofocus" : "", '" + + var tabIndex = canFocus ? '' : ' tabindex="-1"'; + autoFocus = autoFocus ? ' autofocus' : ''; + return ''; } function setUserScalable(scalable) { + try { - appHost.setUserScalable(scalable) - } catch (err) { - console.log("error in appHost.setUserScalable: " + err) + appHost.setUserScalable(scalable); + } + catch (err) { + console.log('error in appHost.setUserScalable: ' + err); } } - return function(options) { + + return function (options) { + + var self = this; + var swiperInstance; + var dlg; + var currentTimeout; + var currentIntervalMs; + var currentOptions; + var currentIndex; + + // small hack since this is not possible anyway + if (browser.chromecast) { + options.interactive = false; + } + function createElements(options) { + dlg = dialogHelper.createDialog({ exitAnimationDuration: options.interactive ? 400 : 800, - size: "fullscreen", - autoFocus: !1, - scrollY: !1, - exitAnimation: "fadeout", - removeOnClose: !0 - }), dlg.classList.add("slideshowDialog"); - var html = ""; + size: 'fullscreen', + autoFocus: false, + scrollY: false, + exitAnimation: 'fadeout', + removeOnClose: true + }); + + dlg.classList.add('slideshowDialog'); + + var html = ''; + if (options.interactive) { + var actionButtonsOnTop = layoutManager.mobile; - html += "
    ", html += '
    ', html += getIcon("keyboard_arrow_left", "btnSlideshowPrevious slideshowButton hide-mouse-idle-tv", !1), html += getIcon("keyboard_arrow_right", "btnSlideshowNext slideshowButton hide-mouse-idle-tv", !1), html += '
    ', actionButtonsOnTop && (appHost.supports("filedownload") && (html += getIcon("file_download", "btnDownload slideshowButton", !0)), appHost.supports("sharing") && (html += getIcon("share", "btnShare slideshowButton", !0))), html += getIcon("close", "slideshowButton btnSlideshowExit hide-mouse-idle-tv", !1), html += "
    ", actionButtonsOnTop || (html += '
    ', html += getIcon("pause", "btnSlideshowPause slideshowButton", !0, !0), appHost.supports("filedownload") && (html += getIcon("file_download", "btnDownload slideshowButton", !0)), appHost.supports("sharing") && (html += getIcon("share", "btnShare slideshowButton", !0)), html += "
    "), html += "
    " - } else html += '

    '; - if (dlg.innerHTML = html, options.interactive) { - dlg.querySelector(".btnSlideshowExit").addEventListener("click", function(e) { - dialogHelper.close(dlg) - }), dlg.querySelector(".btnSlideshowNext").addEventListener("click", nextImage), dlg.querySelector(".btnSlideshowPrevious").addEventListener("click", previousImage); - var btnPause = dlg.querySelector(".btnSlideshowPause"); - btnPause && btnPause.addEventListener("click", playPause); - var btnDownload = dlg.querySelector(".btnDownload"); - btnDownload && btnDownload.addEventListener("click", download); - var btnShare = dlg.querySelector(".btnShare"); - btnShare && btnShare.addEventListener("click", share) + + html += '
    '; + html += '
    '; + + html += getIcon('keyboard_arrow_left', 'btnSlideshowPrevious slideshowButton hide-mouse-idle-tv', false); + html += getIcon('keyboard_arrow_right', 'btnSlideshowNext slideshowButton hide-mouse-idle-tv', false); + + html += '
    '; + if (actionButtonsOnTop) { + if (appHost.supports('filedownload')) { + html += getIcon('file_download', 'btnDownload slideshowButton', true); + } + if (appHost.supports('sharing')) { + html += getIcon('share', 'btnShare slideshowButton', true); + } + } + html += getIcon('close', 'slideshowButton btnSlideshowExit hide-mouse-idle-tv', false); + html += '
    '; + + if (!actionButtonsOnTop) { + html += '
    '; + + html += getIcon('pause', 'btnSlideshowPause slideshowButton', true, true); + if (appHost.supports('filedownload')) { + html += getIcon('file_download', 'btnDownload slideshowButton', true); + } + if (appHost.supports('sharing')) { + html += getIcon('share', 'btnShare slideshowButton', true); + } + + html += '
    '; + } + + html += '
    '; + + } else { + html += '

    '; + } + + dlg.innerHTML = html; + + if (options.interactive) { + dlg.querySelector('.btnSlideshowExit').addEventListener('click', function (e) { + + dialogHelper.close(dlg); + }); + dlg.querySelector('.btnSlideshowNext').addEventListener('click', nextImage); + dlg.querySelector('.btnSlideshowPrevious').addEventListener('click', previousImage); + + var btnPause = dlg.querySelector('.btnSlideshowPause'); + if (btnPause) { + btnPause.addEventListener('click', playPause); + } + + var btnDownload = dlg.querySelector('.btnDownload'); + if (btnDownload) { + btnDownload.addEventListener('click', download); + } + + var btnShare = dlg.querySelector('.btnShare'); + if (btnShare) { + btnShare.addEventListener('click', share); + } + } + + setUserScalable(true); + + dialogHelper.open(dlg).then(function () { + + setUserScalable(false); + stopInterval(); + }); + + inputmanager.on(window, onInputCommand); + document.addEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove); + + dlg.addEventListener('close', onDialogClosed); + + if (options.interactive) { + loadSwiper(dlg); } - setUserScalable(!0), dialogHelper.open(dlg).then(function() { - setUserScalable(!1), stopInterval() - }), inputmanager.on(window, onInputCommand), document.addEventListener(window.PointerEvent ? "pointermove" : "mousemove", onPointerMove), dlg.addEventListener("close", onDialogClosed), options.interactive && loadSwiper(dlg) } function loadSwiper(dlg) { - currentOptions.slides ? dlg.querySelector(".swiper-wrapper").innerHTML = currentOptions.slides.map(getSwiperSlideHtmlFromSlide).join("") : dlg.querySelector(".swiper-wrapper").innerHTML = currentOptions.items.map(getSwiperSlideHtmlFromItem).join(""), require(["swiper"], function(swiper) { - swiperInstance = new Swiper(dlg.querySelector(".slideshowSwiperContainer"), { - direction: "horizontal", - loop: !1 !== options.loop, - autoplay: options.interval || 8e3, - preloadImages: !1, - lazyLoading: !0, - lazyLoadingInPrevNext: !0, - autoplayDisableOnInteraction: !1, + + if (currentOptions.slides) { + dlg.querySelector('.swiper-wrapper').innerHTML = currentOptions.slides.map(getSwiperSlideHtmlFromSlide).join(''); + } else { + dlg.querySelector('.swiper-wrapper').innerHTML = currentOptions.items.map(getSwiperSlideHtmlFromItem).join(''); + } + + require(['swiper'], function (swiper) { + + swiperInstance = new Swiper(dlg.querySelector('.slideshowSwiperContainer'), { + // Optional parameters + direction: 'horizontal', + loop: options.loop !== false, + autoplay: options.interval || 8000, + // Disable preloading of all images + preloadImages: false, + // Enable lazy loading + lazyLoading: true, + lazyLoadingInPrevNext: true, + autoplayDisableOnInteraction: false, initialSlide: options.startIndex || 0, speed: 240 - }), layoutManager.mobile ? pause() : play() - }) + }); + + if (layoutManager.mobile) { + pause(); + } else { + play(); + } + }); } function getSwiperSlideHtmlFromItem(item) { + return getSwiperSlideHtmlFromSlide({ imageUrl: getImgUrl(item), - originalImage: getImgUrl(item, !0), + originalImage: getImgUrl(item, true), + //title: item.Name, + //description: item.Overview Id: item.Id, ServerId: item.ServerId - }) + }); } function getSwiperSlideHtmlFromSlide(item) { - var html = ""; - return html += '
    ', html += '', (item.title || item.subtitle) && (html += '
    ', html += '
    ', item.title && (html += '

    ', html += item.title, html += "

    "), item.description && (html += '
    ', html += item.description, html += "
    "), html += "
    ", html += "
    "), html += "
    " + + var html = ''; + html += '
    '; + html += ''; + if (item.title || item.subtitle) { + html += '
    '; + html += '
    '; + if (item.title) { + html += '

    '; + html += item.title; + html += '

    '; + } + if (item.description) { + html += '
    '; + html += item.description; + html += '
    '; + } + html += '
    '; + html += '
    '; + } + html += '
    '; + + return html; } function previousImage() { - swiperInstance ? swiperInstance.slidePrev() : (stopInterval(), showNextImage(currentIndex - 1)) + if (swiperInstance) { + swiperInstance.slidePrev(); + } else { + stopInterval(); + showNextImage(currentIndex - 1); + } } function nextImage() { if (swiperInstance) { - if (!1 === options.loop && swiperInstance.activeIndex >= swiperInstance.slides.length - 1) return void dialogHelper.close(dlg); - swiperInstance.slideNext() - } else stopInterval(), showNextImage(currentIndex + 1) + + if (options.loop === false) { + + if (swiperInstance.activeIndex >= swiperInstance.slides.length - 1) { + dialogHelper.close(dlg); + return; + } + } + + swiperInstance.slideNext(); + } else { + stopInterval(); + showNextImage(currentIndex + 1); + } } function getCurrentImageInfo() { + if (swiperInstance) { - var slide = document.querySelector(".swiper-slide-active"); - return slide ? { - url: slide.getAttribute("data-original"), - shareUrl: slide.getAttribute("data-imageurl"), - itemId: slide.getAttribute("data-itemid"), - serverId: slide.getAttribute("data-serverid") - } : null + var slide = document.querySelector('.swiper-slide-active'); + + if (slide) { + return { + url: slide.getAttribute('data-original'), + shareUrl: slide.getAttribute('data-imageurl'), + itemId: slide.getAttribute('data-itemid'), + serverId: slide.getAttribute('data-serverid') + }; + } + return null; + } else { + return null; } - return null } function download() { + var imageInfo = getCurrentImageInfo(); - require(["fileDownloader"], function(fileDownloader) { - fileDownloader.download([imageInfo]) - }) + + require(['fileDownloader'], function (fileDownloader) { + fileDownloader.download([imageInfo]); + }); } function share() { + var imageInfo = getCurrentImageInfo(); + navigator.share({ url: imageInfo.shareUrl - }) + }); } function play() { - var btnSlideshowPause = dlg.querySelector(".btnSlideshowPause i"); - btnSlideshowPause && (btnSlideshowPause.innerHTML = "pause"), swiperInstance.startAutoplay() + + var btnSlideshowPause = dlg.querySelector('.btnSlideshowPause i'); + if (btnSlideshowPause) { + btnSlideshowPause.innerHTML = "pause"; + } + + swiperInstance.startAutoplay(); } function pause() { - var btnSlideshowPause = dlg.querySelector(".btnSlideshowPause i"); - btnSlideshowPause && (btnSlideshowPause.innerHTML = "play_arrow"), swiperInstance.stopAutoplay() + + var btnSlideshowPause = dlg.querySelector('.btnSlideshowPause i'); + if (btnSlideshowPause) { + btnSlideshowPause.innerHTML = "play_arrow"; + } + + swiperInstance.stopAutoplay(); } function playPause() { - "pause" !== dlg.querySelector(".btnSlideshowPause i").innerHTML ? play() : pause() + + var paused = dlg.querySelector('.btnSlideshowPause i').innerHTML !== "pause"; + if (paused) { + play(); + } else { + pause(); + } } function onDialogClosed() { + var swiper = swiperInstance; - swiper && (swiper.destroy(!0, !0), swiperInstance = null), inputmanager.off(window, onInputCommand), document.removeEventListener(window.PointerEvent ? "pointermove" : "mousemove", onPointerMove) + if (swiper) { + swiper.destroy(true, true); + swiperInstance = null; + } + + inputmanager.off(window, onInputCommand); + document.removeEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove); } function startInterval(options) { - currentOptions = options, stopInterval(), createElements(options), options.interactive || (currentIntervalMs = options.interval || 11e3, showNextImage(options.startIndex || 0, !0)) + + currentOptions = options; + + stopInterval(); + createElements(options); + + if (!options.interactive) { + currentIntervalMs = options.interval || 11000; + showNextImage(options.startIndex || 0, true); + } } + var _osdOpen = false; + function isOsdOpen() { - return _osdOpen + return _osdOpen; } function getOsdBottom() { - return dlg.querySelector(".slideshowBottomBar") + return dlg.querySelector('.slideshowBottomBar'); } function showOsd() { + var bottom = getOsdBottom(); - bottom && (slideUpToShow(bottom), startHideTimer()) + if (bottom) { + slideUpToShow(bottom); + startHideTimer(); + } } function hideOsd() { + var bottom = getOsdBottom(); - bottom && slideDownToHide(bottom) + if (bottom) { + slideDownToHide(bottom); + } } + var hideTimeout; + function startHideTimer() { - stopHideTimer(), hideTimeout = setTimeout(hideOsd, 4e3) + stopHideTimer(); + hideTimeout = setTimeout(hideOsd, 4000); } function stopHideTimer() { - hideTimeout && (clearTimeout(hideTimeout), hideTimeout = null) + if (hideTimeout) { + clearTimeout(hideTimeout); + hideTimeout = null; + } } function slideUpToShow(elem) { - if (elem.classList.contains("hide")) { - _osdOpen = !0, elem.classList.remove("hide"); - var onFinish = function() { - focusManager.focus(elem.querySelector(".btnSlideshowPause")) - }; - if (!elem.animate) return void onFinish(); - requestAnimationFrame(function() { - var keyframes = [{ - transform: "translate3d(0," + elem.offsetHeight + "px,0)", - opacity: ".3", - offset: 0 - }, { - transform: "translate3d(0,0,0)", - opacity: "1", - offset: 1 - }], - timing = { - duration: 300, - iterations: 1, - easing: "ease-out" - }; - elem.animate(keyframes, timing).onfinish = onFinish - }) + + if (!elem.classList.contains('hide')) { + return; } + + _osdOpen = true; + elem.classList.remove('hide'); + + var onFinish = function () { + focusManager.focus(elem.querySelector('.btnSlideshowPause')); + }; + + if (!elem.animate) { + onFinish(); + return; + } + + requestAnimationFrame(function () { + + var keyframes = [ + { transform: 'translate3d(0,' + elem.offsetHeight + 'px,0)', opacity: '.3', offset: 0 }, + { transform: 'translate3d(0,0,0)', opacity: '1', offset: 1 } + ]; + var timing = { duration: 300, iterations: 1, easing: 'ease-out' }; + elem.animate(keyframes, timing).onfinish = onFinish; + }); } function slideDownToHide(elem) { - if (!elem.classList.contains("hide")) { - var onFinish = function() { - elem.classList.add("hide"), _osdOpen = !1 - }; - if (!elem.animate) return void onFinish(); - requestAnimationFrame(function() { - var keyframes = [{ - transform: "translate3d(0,0,0)", - opacity: "1", - offset: 0 - }, { - transform: "translate3d(0," + elem.offsetHeight + "px,0)", - opacity: ".3", - offset: 1 - }], - timing = { - duration: 300, - iterations: 1, - easing: "ease-out" - }; - elem.animate(keyframes, timing).onfinish = onFinish - }) + + if (elem.classList.contains('hide')) { + return; } + + var onFinish = function () { + elem.classList.add('hide'); + _osdOpen = false; + }; + + if (!elem.animate) { + onFinish(); + return; + } + + requestAnimationFrame(function () { + + var keyframes = [ + { transform: 'translate3d(0,0,0)', opacity: '1', offset: 0 }, + { transform: 'translate3d(0,' + elem.offsetHeight + 'px,0)', opacity: '.3', offset: 1 } + ]; + var timing = { duration: 300, iterations: 1, easing: 'ease-out' }; + elem.animate(keyframes, timing).onfinish = onFinish; + }); } + var lastMouseMoveData; + function onPointerMove(e) { - if ("mouse" === (e.pointerType || (layoutManager.mobile ? "touch" : "mouse"))) { - var eventX = e.screenX || 0, - eventY = e.screenY || 0, - obj = lastMouseMoveData; - if (!obj) return void(lastMouseMoveData = { - x: eventX, - y: eventY - }); - if (Math.abs(eventX - obj.x) < 10 && Math.abs(eventY - obj.y) < 10) return; - obj.x = eventX, obj.y = eventY, showOsd() + + var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse'); + + if (pointerType === 'mouse') { + var eventX = e.screenX || 0; + var eventY = e.screenY || 0; + + var obj = lastMouseMoveData; + if (!obj) { + lastMouseMoveData = { + x: eventX, + y: eventY + }; + return; + } + + // if coord are same, it didn't move + if (Math.abs(eventX - obj.x) < 10 && Math.abs(eventY - obj.y) < 10) { + return; + } + + obj.x = eventX; + obj.y = eventY; + + showOsd(); } } function onInputCommand(e) { + switch (e.detail.command) { - case "left": - isOsdOpen() || (e.preventDefault(), e.stopPropagation(), previousImage()); + + case 'left': + if (!isOsdOpen()) { + e.preventDefault(); + e.stopPropagation(); + previousImage(); + } break; - case "right": - isOsdOpen() || (e.preventDefault(), e.stopPropagation(), nextImage()); + case 'right': + if (!isOsdOpen()) { + e.preventDefault(); + e.stopPropagation(); + nextImage(); + } + break; + case 'up': + case 'down': + case 'select': + case 'menu': + case 'info': + case 'play': + case 'playpause': + case 'pause': + showOsd(); + break; + default: break; - case "up": - case "down": - case "select": - case "menu": - case "info": - case "play": - case "playpause": - case "pause": - showOsd() } } function showNextImage(index, skipPreload) { - index = Math.max(0, index), index >= currentOptions.items.length && (index = 0), currentIndex = index; - var options = currentOptions, - items = options.items, - item = items[index], - imgUrl = getImgUrl(item), - onSrcLoaded = function() { - var cardImageContainer = dlg.querySelector(".slideshowImage"), - newCardImageContainer = document.createElement("div"); - newCardImageContainer.className = cardImageContainer.className, options.cover && newCardImageContainer.classList.add("slideshowImage-cover"), newCardImageContainer.style.backgroundImage = "url('" + imgUrl + "')", newCardImageContainer.classList.add("hide"), cardImageContainer.parentNode.appendChild(newCardImageContainer), options.showTitle ? dlg.querySelector(".slideshowImageText").innerHTML = item.Name : dlg.querySelector(".slideshowImageText").innerHTML = "", newCardImageContainer.classList.remove("hide"); - var onAnimationFinished = function() { - var parentNode = cardImageContainer.parentNode; - parentNode && parentNode.removeChild(cardImageContainer) - }; - if (newCardImageContainer.animate) { - var keyframes = [{ - opacity: "0", - offset: 0 - }, { - opacity: "1", - offset: 1 - }], - timing = { - duration: 1200, - iterations: 1 - }; - newCardImageContainer.animate(keyframes, timing).onfinish = onAnimationFinished - } else onAnimationFinished(); - stopInterval(), currentTimeout = setTimeout(function() { - showNextImage(index + 1, !0) - }, currentIntervalMs) + + index = Math.max(0, index); + if (index >= currentOptions.items.length) { + index = 0; + } + currentIndex = index; + + var options = currentOptions; + var items = options.items; + var item = items[index]; + var imgUrl = getImgUrl(item); + + var onSrcLoaded = function () { + var cardImageContainer = dlg.querySelector('.slideshowImage'); + + var newCardImageContainer = document.createElement('div'); + newCardImageContainer.className = cardImageContainer.className; + + if (options.cover) { + newCardImageContainer.classList.add('slideshowImage-cover'); + } + + newCardImageContainer.style.backgroundImage = "url('" + imgUrl + "')"; + newCardImageContainer.classList.add('hide'); + cardImageContainer.parentNode.appendChild(newCardImageContainer); + + if (options.showTitle) { + dlg.querySelector('.slideshowImageText').innerHTML = item.Name; + } else { + dlg.querySelector('.slideshowImageText').innerHTML = ''; + } + + newCardImageContainer.classList.remove('hide'); + var onAnimationFinished = function () { + + var parentNode = cardImageContainer.parentNode; + if (parentNode) { + parentNode.removeChild(cardImageContainer); + } }; - if (skipPreload) onSrcLoaded(); - else { - var img = new Image; - img.onload = onSrcLoaded, img.src = imgUrl + + if (newCardImageContainer.animate) { + + var keyframes = [ + { opacity: '0', offset: 0 }, + { opacity: '1', offset: 1 } + ]; + var timing = { duration: 1200, iterations: 1 }; + newCardImageContainer.animate(keyframes, timing).onfinish = onAnimationFinished; + } else { + onAnimationFinished(); + } + + stopInterval(); + currentTimeout = setTimeout(function () { + showNextImage(index + 1, true); + + }, currentIntervalMs); + }; + + if (!skipPreload) { + var img = new Image(); + img.onload = onSrcLoaded; + img.src = imgUrl; + } else { + onSrcLoaded(); } } function stopInterval() { - currentTimeout && (clearTimeout(currentTimeout), currentTimeout = null) + if (currentTimeout) { + clearTimeout(currentTimeout); + currentTimeout = null; + } } - var swiperInstance, dlg, currentTimeout, currentIntervalMs, currentOptions, currentIndex, self = this; - browser.chromecast && (options.interactive = !1); - var hideTimeout, lastMouseMoveData, _osdOpen = !1; - self.show = function() { - startInterval(options) - }, self.hide = function() { + + self.show = function () { + startInterval(options); + }; + + self.hide = function () { + var dialog = dlg; - dialog && dialogHelper.close(dialog) - } - } + if (dialog) { + + dialogHelper.close(dialog); + } + }; + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/slideshow/style.css b/src/bower_components/emby-webcomponents/slideshow/style.css index 85cae77d29..43211a8fef 100644 --- a/src/bower_components/emby-webcomponents/slideshow/style.css +++ b/src/bower_components/emby-webcomponents/slideshow/style.css @@ -1,29 +1,28 @@ -.slideshowDialog, -.slideshowSwiperContainer, -.swiper-slide, -.swiper-wrapper { - background: #000 +.slideshowDialog { + /* Themes may use non-black backgrounds for dialogs, so override that here */ + background: #000; } -.slideshowImage, -.slideshowSwiperContainer { +.slideshowSwiperContainer, .swiper-wrapper, .swiper-slide { + background: #000; +} + +.slideshowImage, .slideshowSwiperContainer { position: fixed; top: 0; right: 0; left: 0; bottom: 0; background-position: center center; - -webkit-background-size: contain; background-size: contain; background-repeat: no-repeat; margin: 0 !important; color: #fff; - line-height: normal + line-height: normal; } .slideshowImage-cover { - -webkit-background-size: cover; - background-size: cover + background-size: cover; } .slideshowImageText { @@ -32,8 +31,9 @@ right: .5em; color: #fff; z-index: 1002; - font-weight: 400; - text-shadow: 3px 3px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000 + font-weight: normal; + /* Add an outline */ + text-shadow: 3px 3px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; } .swiper-slide-img { @@ -41,86 +41,73 @@ height: auto; max-width: 100%; max-height: 100%; + -ms-transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); transform: translate(-50%, -50%); position: absolute; left: 50%; - top: 50% -} - -.btnSlideshowNext, -.btnSlideshowPrevious { - top: 45vh; - z-index: 1002; - position: absolute + top: 50%; } .slideshowButtonIcon { color: #fff; - opacity: .7 + opacity: .7; } .btnSlideshowPrevious { - left: .5vh + left: .5vh; + top: 45vh; + z-index: 1002; + position: absolute; } .btnSlideshowNext { - right: .5vh + right: .5vh; + top: 45vh; + z-index: 1002; + position: absolute; } .topActionButtons { right: .5vh; top: .5vh; z-index: 1002; - position: absolute -} - -.slideshowBottomBar, -.slideshowTopBar { - position: fixed; - background-color: rgba(0, 0, 0, .7); - color: #fff; - padding: .5%; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - left: 0; - right: 0 + position: absolute; } .slideshowBottomBar { + position: fixed; + left: 0; bottom: 0; - display: -webkit-box; - display: -webkit-flex; + right: 0; + background-color: rgba(0, 0, 0, .7); + color: #fff; + padding: .5%; display: flex; - -webkit-flex-direction: row; flex-direction: row; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; - justify-content: center + justify-content: center; } .slideshowTopBar { + position: fixed; + left: 0; top: 0; - display: -webkit-box; - display: -webkit-flex; + right: 0; + background-color: rgba(0, 0, 0, .7); + color: #fff; + padding: .5%; display: flex; - -webkit-flex-direction: row; flex-direction: row; - -webkit-box-align: center; - -webkit-align-items: center; align-items: center; text-align: right; - -webkit-box-pack: end; - -webkit-justify-content: flex-end; - justify-content: flex-end + justify-content: flex-end; } .slideshowExtraButtons { margin-left: auto; - text-align: right + text-align: right; } .slideText { @@ -128,23 +115,22 @@ left: 0; right: 0; bottom: 10vh; - text-align: center + text-align: center; } .slideTextInner { margin: 0 auto; max-width: 60%; - background: rgba(0, 0, 0, .8); + background: rgba(0,0,0,.8); display: inline-block; padding: .5em 1em; - -webkit-border-radius: .25em; - border-radius: .25em + border-radius: .25em; } .slideTitle { - margin: 0 0 .25em + margin: 0 0 .25em; } .slideSubtitle { - color: #ccc -} \ No newline at end of file + color: #ccc; +} diff --git a/src/bower_components/emby-webcomponents/sortmenu/sortmenu.js b/src/bower_components/emby-webcomponents/sortmenu/sortmenu.js index b2298230d9..2dd08cf481 100644 --- a/src/bower_components/emby-webcomponents/sortmenu/sortmenu.js +++ b/src/bower_components/emby-webcomponents/sortmenu/sortmenu.js @@ -1,54 +1,124 @@ -define(["require", "dom", "focusManager", "dialogHelper", "loading", "layoutManager", "connectionManager", "globalize", "userSettings", "emby-select", "paper-icon-button-light", "material-icons", "css!./../formdialog", "emby-button", "emby-linkbutton", "flexStyles"], function(require, dom, focusManager, dialogHelper, loading, layoutManager, connectionManager, globalize, userSettings) { - "use strict"; +define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutManager', 'connectionManager', 'globalize', 'userSettings', 'emby-select', 'paper-icon-button-light', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, layoutManager, connectionManager, globalize, userSettings) { + 'use strict'; function onSubmit(e) { - return e.preventDefault(), !1 + + e.preventDefault(); + return false; } function initEditor(context, settings) { - context.querySelector("form").addEventListener("submit", onSubmit), context.querySelector(".selectSortOrder").value = settings.sortOrder, context.querySelector(".selectSortBy").value = settings.sortBy + + context.querySelector('form').addEventListener('submit', onSubmit); + + context.querySelector('.selectSortOrder').value = settings.sortOrder; + context.querySelector('.selectSortBy').value = settings.sortBy; } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function fillSortBy(context, options) { - context.querySelector(".selectSortBy").innerHTML = options.map(function(o) { - return '" - }).join("") + var selectSortBy = context.querySelector('.selectSortBy'); + + selectSortBy.innerHTML = options.map(function (o) { + + return ''; + + }).join(''); } function saveValues(context, settings, settingsKey) { - userSettings.setFilter(settingsKey + "-sortorder", context.querySelector(".selectSortOrder").value), userSettings.setFilter(settingsKey + "-sortby", context.querySelector(".selectSortBy").value) + + userSettings.setFilter(settingsKey + '-sortorder', context.querySelector('.selectSortOrder').value); + userSettings.setFilter(settingsKey + '-sortby', context.querySelector('.selectSortBy').value); } - function SortMenu() {} - return SortMenu.prototype.show = function(options) { - return new Promise(function(resolve, reject) { - require(["text!./sortmenu.template.html"], function(template) { + function SortMenu() { + + } + + SortMenu.prototype.show = function (options) { + + return new Promise(function (resolve, reject) { + + require(['text!./sortmenu.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'small'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - var html = ""; - html += '
    ', html += '', html += '

    ${Sort}

    ', html += "
    ", html += template, dlg.innerHTML = globalize.translateDocument(html, "sharedcomponents"), fillSortBy(dlg, options.sortOptions), initEditor(dlg, options.settings), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0); + + dlg.classList.add('formDialog'); + + var html = ''; + + html += '
    '; + html += ''; + html += '

    ${Sort}

    '; + + html += '
    '; + + html += template; + + dlg.innerHTML = globalize.translateDocument(html, 'sharedcomponents'); + + fillSortBy(dlg, options.sortOptions); + initEditor(dlg, options.settings); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + var submitted; - dlg.querySelector("form").addEventListener("change", function() { - submitted = !0 - }, !0), dialogHelper.open(dlg).then(function() { - if (layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), submitted) return saveValues(dlg, options.settings, options.settingsKey), void resolve(); - reject() - }) - }) - }) - }, SortMenu + + dlg.querySelector('form').addEventListener('change', function () { + + submitted = true; + //if (options.onChange) { + // saveValues(dlg, options.settings, options.settingsKey); + // options.onChange(); + //} + + }, true); + + dialogHelper.open(dlg).then(function () { + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + if (submitted) { + + //if (!options.onChange) { + saveValues(dlg, options.settings, options.settingsKey); + resolve(); + //} + return; + } + + reject(); + }); + }); + }); + }; + + return SortMenu; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/staticbackdrops.js b/src/bower_components/emby-webcomponents/staticbackdrops.js index 62a9a1f71d..f69d0109b2 100644 --- a/src/bower_components/emby-webcomponents/staticbackdrops.js +++ b/src/bower_components/emby-webcomponents/staticbackdrops.js @@ -1,66 +1,129 @@ -define([], function() { - "use strict"; +define([], function () { + 'use strict'; function getStaticBackdrops() { var list = []; - return list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg1-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg2-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg3-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg4-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg5-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg6-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg7-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg8-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg9-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg10-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg11-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg12-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg13-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg14-1920.jpg", - width: 1920 - }]), list.push([{ - url: "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg15-1920.jpg", - width: 1920 - }]), list + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg1-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg2-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg3-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg4-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg5-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg6-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg7-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg8-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg9-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg10-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg11-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg12-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg13-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg14-1920.jpg', + width: 1920 + } + ]); + + list.push([ + { + url: 'https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/wallpaper/bg15-1920.jpg', + width: 1920 + } + ]); + + return list; } function getRandomInt(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min + return Math.floor(Math.random() * (max - min + 1)) + min; } function getRandomImageUrl() { var images = getStaticBackdrops(); - return images[getRandomInt(0, images.length - 1)][0].url + var index = getRandomInt(0, images.length - 1); + return images[index][0].url; } + return { getStaticBackdrops: getStaticBackdrops, getRandomImageUrl: getRandomImageUrl - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/ar.json b/src/bower_components/emby-webcomponents/strings/ar.json index fcc1670523..8be6d009da 100644 --- a/src/bower_components/emby-webcomponents/strings/ar.json +++ b/src/bower_components/emby-webcomponents/strings/ar.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "الغاء", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "الجمعة", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "البلد:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "اللغة:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "الاثنين", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "السبت", - "Save": "تخزين", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "الاحد", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "الخميس", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "الثلاثاء", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "الاربعاء", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "\u0627\u0644\u063a\u0627\u0621", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "\u0627\u0644\u0627\u062d\u062f", + "Monday": "\u0627\u0644\u0627\u062b\u0646\u064a\u0646", + "Tuesday": "\u0627\u0644\u062b\u0644\u0627\u062b\u0627\u0621", + "Wednesday": "\u0627\u0644\u0627\u0631\u0628\u0639\u0627\u0621", + "Thursday": "\u0627\u0644\u062e\u0645\u064a\u0633", + "Friday": "\u0627\u0644\u062c\u0645\u0639\u0629", + "Saturday": "\u0627\u0644\u0633\u0628\u062a", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "\u062a\u062e\u0632\u064a\u0646", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "\u0627\u0644\u0644\u063a\u0629:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "\u0627\u0644\u0628\u0644\u062f:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/be-by.json b/src/bower_components/emby-webcomponents/strings/be-by.json index cf046fb941..b775d9a047 100644 --- a/src/bower_components/emby-webcomponents/strings/be-by.json +++ b/src/bower_components/emby-webcomponents/strings/be-by.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Адмяніць", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friday", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Country:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Language:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Monday", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Saturday", - "Save": "Save", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Sunday", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Thursday", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tuesday", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Wednesday", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "\u0410\u0434\u043c\u044f\u043d\u0456\u0446\u044c", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Save", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Language:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Country:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/bg-bg.json b/src/bower_components/emby-webcomponents/strings/bg-bg.json index db408e1018..b4d44de4ae 100644 --- a/src/bower_components/emby-webcomponents/strings/bg-bg.json +++ b/src/bower_components/emby-webcomponents/strings/bg-bg.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Актьор", - "Add": "Добавяне", - "AddToCollection": "Добавяне към колекция", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Добавяне към списък", - "AddedOnValue": "Добавено на {0}", - "Advanced": "Разширени", - "AirDate": "Дата на излъчване", - "Aired": "Излъчено", - "Albums": "Албуми", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Автоматични сезонни облици", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Картина", - "Artists": "Изпълнители", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "Нови", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Автоматично", - "AutoBasedOnLanguageSetting": "Автоматично (според езика)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Автоматично сваляне на ново съдържание", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Фон", - "Backdrops": "Фонове", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Книги", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Разглеждане", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Отмяна", - "ButtonGotIt": "Добре", - "ButtonOk": "Добре", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Повторно пускане", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Опитайте отново", - "ButtonUnlockPrice": "Отключване на {0}", - "ButtonUnlockWithPurchase": "Отключване с покупка", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Колекции", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Цветово пространство", - "ColorTransfer": "Color transfer", - "CommunityRating": "Обществена ощенка", - "Composer": "Съчинител", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Изтриване на изображението?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Продължаване", - "ContinueInSecondsValue": "Продължаване след {0} секунди.", - "ContinueWatching": "Продължаване на гледането", - "Continuing": "Продължаващо", - "Convert": "Преобразуване", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Държави", - "CriticRating": "Оценка на критиците", - "DateAdded": "Дата на добавяне", - "DatePlayed": "Дата на пускане", - "Days": "Дни", - "Default": "По подразбиране", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Изтриване", - "DeleteMedia": "Изтриване на медията", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Работен плот", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Режисьор", - "DirectorValue": "Режисьор: {0}", - "DirectorsValue": "Режисьори: {0}", - "Disc": "Диск", - "Disconnect": "Disconnect", - "Dislike": "Нехаресване", - "Display": "Показване", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Изтегляне", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Изтеглени", - "Downloading": "Изтегляне", - "DownloadingDots": "Изтегляне...", - "Downloads": "Изтегляния", - "DownloadsValue": "{0} изтегляния", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Редактиране", - "EditImages": "Редактиране на изображенията", - "EditMetadata": "Редактиране на метаданните", - "EditSubtitles": "Редактиране на субтитрите", - "EnableBackdrops": "Фонове", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Включване на режим \"Киносалон\"", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Тематични песни", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Приключило", - "EndsAtValue": "Свършва на {0}", - "Episodes": "Епизоди", - "Error": "Грешка", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Много голям", - "Extras": "Екстри", - "Favorite": "В любими", - "Favorites": "Любими", - "FeatureRequiresJellyfinPremiere": "Функцията изисква активен абонамент за премиерното издание на Емби.", - "Features": "Features", - "File": "Файл", - "Fill": "Fill", - "Filters": "Филтри", - "Folders": "Folders", - "FormatValue": "Формат: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Петък", - "GenreValue": "Жанр: {0}", - "Genres": "Жанрове", - "GenresValue": "Жанрове: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Групиране на версиите", - "GuestStar": "Гостуваща звезда", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Справочник", - "HDPrograms": "Програми с висока разделителна способност", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Добавяне към колекция", - "HeaderAddToPlaylist": "Добавяне към списък", - "HeaderAddUpdateImage": "Добавяне/редактиране на изображение", - "HeaderAlbumArtists": "Изпълнители на албуми", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Настройки на звука", - "HeaderBecomeProjectSupporter": "Вземете премиерното издание", - "HeaderBenefitsJellyfinPremiere": "Предимства на премиерното издание", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Режим \"Киносалон\"", - "HeaderCloudSync": "Синхронизиране в облака", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Продължаване на слушането", - "HeaderContinueWatching": "Продължаване на гледането", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Настройки на показване", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Редактиране на изображенията", - "HeaderEnabledFields": "Включени полета", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Любими албуми", - "HeaderFavoriteArtists": "Любими изпълнители", - "HeaderFavoriteCollections": "Любими колекции", - "HeaderFavoriteEpisodes": "Любими епизоди", - "HeaderFavoriteGames": "Любими игри", - "HeaderFavoriteMovies": "Любими филми", - "HeaderFavoritePlaylists": "Любими списъци", - "HeaderFavoriteShows": "Любими предавания", - "HeaderFavoriteSongs": "Любими песни", - "HeaderFavoriteVideos": "Любими клипове", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Начален екран", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Поканата е изпратена", - "HeaderJellyfinAccountAdded": "Сметката в Емби е добавена", - "HeaderJellyfinAccountRemoved": "Сметката в Емби е премахната", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Последни медии", - "HeaderLatestRecordings": "Последни записи", - "HeaderLearnMore": "Научете повече", - "HeaderLibraryFolders": "Папки на библиотеката", - "HeaderLibraryOrder": "Подредба на библиотеката", - "HeaderMetadataSettings": "Настройки на метаданните", - "HeaderMusicQuality": "Качество на музиката", - "HeaderMyDevice": "Моето устройство", - "HeaderMyDownloads": "Моите изтегляния", - "HeaderMyMedia": "Моята медия", - "HeaderMyMediaSmall": "Моята медия (малък)", - "HeaderNewRecording": "Нов запис", - "HeaderNextEpisodePlayingInValue": "Следващият епизод ще се пусне след {0}", - "HeaderNextUp": "Следва", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "На живо сега", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Пускане на", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} секунди", - "HeaderSelectDate": "Избиране на дата", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Пускане веднага", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Облик на субтитрите", - "HeaderSubtitleSettings": "Настройки на субтитрите", - "HeaderSyncRequiresSub": "Изтеглянето изисква активен абонамент за премиерното издание.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Отключване на функцията", - "HeaderUploadImage": "Качване на изображение", - "HeaderVideoQuality": "Качество на видеото", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Помощ", - "Hide": "Скриване", - "HideWatchedContentFromLatestMedia": "Скриване на гледаното съдържание от последната медия", - "Home": "Начало", - "Horizontal": "Водоравно", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "Имам премиерно издание", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Разпознаване", - "Images": "Изображения", - "ImdbRating": "Оценка в IMDb", - "InstallingPackage": "Инсталиране на {0}", - "InstantMix": "Пускане на подобни", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "Триизмерен формат:", - "LabelAirDays": "Дни на излъчване:", - "LabelAirTime": "Час на излъчване:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Албум:", - "LabelAlbumArtists": "Изпълнители на албума:", - "LabelArtists": "Изпълнители:", - "LabelArtistsHelp": "Отделете няколко с ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Предпочитан език на звука:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Колекция:", - "LabelCommunityRating": "Обществена оценка", - "LabelContentType": "Тип на съдържанието:", - "LabelConvertTo": "Преобразуване в:", - "LabelCountry": "Държава:", - "LabelCriticRating": "Оценка на критиците:", - "LabelCustomRating": "Оценка по избор:", - "LabelDashboardTheme": "Облик на сървърното табло:", - "LabelDateAdded": "Дата на добавяне:", - "LabelDateTimeLocale": "Местоположение за дата и час:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Език на показване:", - "LabelDisplayLanguageHelp": "Превеждането на Емби е текущ проект.", - "LabelDisplayMode": "Режим на показване:", - "LabelDisplayOrder": "Ред на показване:", - "LabelDropImageHere": "Пуснете изображение тук или щракнете за разглеждане.", - "LabelDropShadow": "Сянка:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "Електронна поща:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Номер на епизода:", - "LabelFont": "Шрифт:", - "LabelHomeNetworkQuality": "Качество на домашната мрежа:", - "LabelHomeScreenSectionValue": "Раздел {0} на началния екран:", - "LabelImageType": "Вид изображение:", - "LabelInternetQuality": "Качество на интернетната връзка:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Език:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Предпочитан език на сваляне:", - "LabelName": "Име:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Оригинално съотношение:", - "LabelOriginalTitle": "Оригинално заглавие:", - "LabelOverview": "Обобщение:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Родителска оценка:", - "LabelPath": "Път:", - "LabelPersonRole": "Роля:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Рождено място:", - "LabelPlayDefaultAudioTrack": "Да се пуска първоначалната звукова пътечка независимо от езика", - "LabelPlaylist": "Списък:", - "LabelPreferredSubtitleLanguage": "Предпочитан език на субтитрите:", - "LabelProfile": "Profile:", - "LabelQuality": "Качество:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Дата на издаване:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Номер на сезона:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Кратко обобщение:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Подреждане по:", - "LabelSortOrder": "Ред на подреждане", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Състояние:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Режим на субтитрите:", - "LabelSubtitles": "Субтитри:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Синхронизиране към:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Цвят на текста:", - "LabelTextSize": "Размер на текста:", - "LabelTheme": "Облик:", - "LabelTitle": "Заглавие:", - "LabelTrackNumber": "Track number:", - "LabelType": "Вид:", - "LabelVersion": "Версия:", - "LabelVideo": "Video:", - "LabelWebsite": "Сайт:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Година:", - "Large": "Голям", - "LatestFromLibrary": "Последни {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Научете повече", - "Like": "Харесване", - "LinksValue": "Препратки: {0}", - "List": "Списък", - "Live": "На живо", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Телевизия на живо", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Телевизията на живо изисква активен абонамент за премиерното издание.", - "Logo": "Логотип", - "ManageRecording": "Manage recording", - "MarkPlayed": "Отбелязване като пускано", - "MarkUnplayed": "Отбелязване като непускано", - "MarkWatched": "Отбелязване като изгледано", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Меню", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "Няма изтегляния. Създайте задачи чрез копчетата за сваляне.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "минути след", - "MinutesBefore": "минути преди", - "Mobile": "Мобилно устройство", - "Monday": "Понеделник", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Филми", - "MySubtitles": "Моите субтитри", - "Name": "Име", - "NewCollection": "Нова колекция", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Пример: колекция Междузвездни войни", - "NewEpisodes": "Нови епизоди", - "NewEpisodesOnly": "Само нови епизоди", - "News": "Новини", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "Няма намерени резултати.", - "NoSubtitles": "Без субтитри", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "Нищо", - "Normal": "Нормален", - "Off": "Изключено", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Отваряне", - "OptionNew": "Нов...", - "Original": "Original", - "OriginalAirDateValue": "Дата на първоначално излъчване: {0}", - "Overview": "Обобщение", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Родителска оценка", - "People": "Хора", - "PerfectMatch": "Perfect match", - "Photos": "Снимки", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Пускане", - "PlayAllFromHere": "Пускане на всичко от тук", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Автоматично пускане на следващия епизод", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Пускано", - "Playlists": "Списъци", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Моля, пуснете сървъра отново - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Премиера", - "Premieres": "Премиери", - "Previous": "Previous", - "Primary": "Главно", - "PrivacyPolicy": "Privacy policy", - "Producer": "Продуцент", - "ProductionLocations": "Production locations", - "Programs": "Програми", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Качество", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Скоро гледани", - "Record": "Записване", - "RecordSeries": "Record series", - "RecordingCancelled": "Записването е отказано.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Опресняване", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Опресняване на метаданните", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Дата на издаване", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Премахване от колекцията", - "RemoveFromPlaylist": "Премахване от списъка", - "RemovingFromDevice": "Removing from device", - "Repeat": "Повтаряне", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Продължаване от {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Времетраене", - "Saturday": "Събота", - "Save": "Запазване", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Разписание", - "Screenshot": "Снимка на екрана", - "Screenshots": "Снимки на екрана", - "Search": "Търсене", - "SearchForCollectionInternetMetadata": "Търсене в интернет за картини и метаданни", - "SearchForMissingMetadata": "Търсене за лисващи метаданни", - "SearchForSubtitles": "Търсене на субтитри", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Настояще", - "ServerNameIsRestarting": "Сървърно издание Емби - {0} се пуска повторно.", - "ServerNameIsShuttingDown": "Сървърно издание Емби - {0} се изключва.", - "ServerUpdateNeeded": "Сървърът трябва да бъде обновен. Моля, посетете {0}, за да свалите последната версия.", - "Settings": "Настройки", - "SettingsSaved": "Настройките са запазени.", - "Share": "Споделяне", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Показване на заглавието", - "ShowYear": "Показване на годината", - "Shows": "Предавания", - "Shuffle": "Пускане в разбъркан ред", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Малък", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Умни", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Песни", - "Sort": "Подреждане", - "SortByValue": "Подреждане по {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Спортни", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Студиа", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Субтитри", - "Suggestions": "Предложения", - "Sunday": "Неделя", - "Sync": "Синхронизиране", - "SyncJobItemStatusCancelled": "Отказано", - "SyncJobItemStatusConverting": "Преобразуване", - "SyncJobItemStatusFailed": "Провалено", - "SyncJobItemStatusQueued": "В опашка", - "SyncJobItemStatusReadyToTransfer": "В готовност за прехвърляне", - "SyncJobItemStatusRemovedFromDevice": "Премахнато", - "SyncJobItemStatusSynced": "Изтеглено", - "SyncJobItemStatusSyncedMarkForRemoval": "Премахване от устройството", - "SyncJobItemStatusTransferring": "Прехвърляне", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "Телевизор", - "Tags": "Етикети", - "TagsValue": "Етикети: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Фонови песни", - "ThemeVideos": "Фонови видеоклипове", - "TheseSettingsAffectSubtitlesOnThisDevice": "Тези настройки променят субтитрите на текущото устройство", - "Thumb": "Миниатюра", - "Thursday": "Четвъртък", - "TrackCount": "{0} песни", - "Trailer": "Трейлър", - "Trailers": "Трейлъри", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Вторник", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Непускано", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Качване", - "ValueAlbumCount": "{0} албума", - "ValueDiscNumber": "Диск {0}", - "ValueEpisodeCount": "{0} епизода", - "ValueGameCount": "{0} игри", - "ValueMinutes": "{0} минути", - "ValueMovieCount": "{0} филма", - "ValueMusicVideoCount": "{0} музикални клипа", - "ValueOneAlbum": "1 албум", - "ValueOneEpisode": "1 епизод", - "ValueOneGame": "1 игра", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 филм", - "ValueOneMusicVideo": "1 музикален клип", - "ValueOneSeries": "1 сериал", - "ValueOneSong": "1 песен", - "ValueSeconds": "{0} секунди", - "ValueSeriesCount": "{0} сериала", - "ValueSongCount": "{0} песни", - "ValueSpecialEpisodeName": "Специални - {0}", - "Vertical": "Отвесно", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "Преглед на албума", - "ViewArtist": "Преглед на изпълнителя", - "VoiceInput": "Voice Input", - "WakeServer": "Събуждане", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Изгледано", - "Wednesday": "Сряда", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Писател", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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": "\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u043d\u0438 - {0}", + "Share": "\u0421\u043f\u043e\u0434\u0435\u043b\u044f\u043d\u0435", + "Add": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435", + "ServerUpdateNeeded": "\u0421\u044a\u0440\u0432\u044a\u0440\u044a\u0442 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0431\u044a\u0434\u0435 \u043e\u0431\u043d\u043e\u0432\u0435\u043d. \u041c\u043e\u043b\u044f, \u043f\u043e\u0441\u0435\u0442\u0435\u0442\u0435 {0}, \u0437\u0430 \u0434\u0430 \u0441\u0432\u0430\u043b\u0438\u0442\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044f.", + "LiveTvRequiresUnlock": "\u0422\u0435\u043b\u0435\u0432\u0438\u0437\u0438\u044f\u0442\u0430 \u043d\u0430 \u0436\u0438\u0432\u043e \u0438\u0437\u0438\u0441\u043a\u0432\u0430 \u0430\u043a\u0442\u0438\u0432\u0435\u043d \u0430\u0431\u043e\u043d\u0430\u043c\u0435\u043d\u0442 \u0437\u0430 \u043f\u0440\u0435\u043c\u0438\u0435\u0440\u043d\u043e\u0442\u043e \u0438\u0437\u0434\u0430\u043d\u0438\u0435.", + "AttributeNew": "\u041d\u043e\u0432\u0438", + "Premiere": "\u041f\u0440\u0435\u043c\u0438\u0435\u0440\u0430", + "Live": "\u041d\u0430 \u0436\u0438\u0432\u043e", + "Repeat": "\u041f\u043e\u0432\u0442\u0430\u0440\u044f\u043d\u0435", + "TrackCount": "{0} \u043f\u0435\u0441\u043d\u0438", + "ItemCount": "{0} items", + "OriginalAirDateValue": "\u0414\u0430\u0442\u0430 \u043d\u0430 \u043f\u044a\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u043d\u043e \u0438\u0437\u043b\u044a\u0447\u0432\u0430\u043d\u0435: {0}", + "EndsAtValue": "\u0421\u0432\u044a\u0440\u0448\u0432\u0430 \u043d\u0430 {0}", + "HeaderSelectDate": "\u0418\u0437\u0431\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0434\u0430\u0442\u0430", + "Watched": "\u0418\u0437\u0433\u043b\u0435\u0434\u0430\u043d\u043e", + "AirDate": "\u0414\u0430\u0442\u0430 \u043d\u0430 \u0438\u0437\u043b\u044a\u0447\u0432\u0430\u043d\u0435", + "Played": "\u041f\u0443\u0441\u043a\u0430\u043d\u043e", + "ButtonOk": "\u0414\u043e\u0431\u0440\u0435", + "ButtonCancel": "\u041e\u0442\u043c\u044f\u043d\u0430", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "\u0414\u043e\u0431\u0440\u0435", + "ButtonRestart": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u043f\u0443\u0441\u043a\u0430\u043d\u0435", + "RecordingCancelled": "\u0417\u0430\u043f\u0438\u0441\u0432\u0430\u043d\u0435\u0442\u043e \u0435 \u043e\u0442\u043a\u0430\u0437\u0430\u043d\u043e.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "\u041d\u043e\u0432 \u0437\u0430\u043f\u0438\u0441", + "WakeServer": "\u0421\u044a\u0431\u0443\u0436\u0434\u0430\u043d\u0435", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "\u041d\u0435\u0434\u0435\u043b\u044f", + "Monday": "\u041f\u043e\u043d\u0435\u0434\u0435\u043b\u043d\u0438\u043a", + "Tuesday": "\u0412\u0442\u043e\u0440\u043d\u0438\u043a", + "Wednesday": "\u0421\u0440\u044f\u0434\u0430", + "Thursday": "\u0427\u0435\u0442\u0432\u044a\u0440\u0442\u044a\u043a", + "Friday": "\u041f\u0435\u0442\u044a\u043a", + "Saturday": "\u0421\u044a\u0431\u043e\u0442\u0430", + "Days": "\u0414\u043d\u0438", + "SortByValue": "\u041f\u043e\u0434\u0440\u0435\u0436\u0434\u0430\u043d\u0435 \u043f\u043e {0}", + "LabelSortBy": "\u041f\u043e\u0434\u0440\u0435\u0436\u0434\u0430\u043d\u0435 \u043f\u043e:", + "LabelSortOrder": "\u0420\u0435\u0434 \u043d\u0430 \u043f\u043e\u0434\u0440\u0435\u0436\u0434\u0430\u043d\u0435", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "\u0421\u043d\u0438\u043c\u043a\u0438", + "HeaderAppearsOn": "Appears On", + "List": "\u0421\u043f\u0438\u0441\u044a\u043a", + "RecordSeries": "Record series", + "HeaderCinemaMode": "\u0420\u0435\u0436\u0438\u043c \"\u041a\u0438\u043d\u043e\u0441\u0430\u043b\u043e\u043d\"", + "HeaderCloudSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0430\u043d\u0435 \u0432 \u043e\u0431\u043b\u0430\u043a\u0430", + "Downloads": "\u0418\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0438\u044f", + "HeaderMyDownloads": "\u041c\u043e\u0438\u0442\u0435 \u0438\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0438\u044f", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "\u0412\u0437\u0435\u043c\u0435\u0442\u0435 \u043f\u0440\u0435\u043c\u0438\u0435\u0440\u043d\u043e\u0442\u043e \u0438\u0437\u0434\u0430\u043d\u0438\u0435", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "LabelEmailAddress": "\u0415\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u0430 \u043f\u043e\u0449\u0430:", + "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": "\u0424\u0443\u043d\u043a\u0446\u0438\u044f\u0442\u0430 \u0438\u0437\u0438\u0441\u043a\u0432\u0430 \u0430\u043a\u0442\u0438\u0432\u0435\u043d \u0430\u0431\u043e\u043d\u0430\u043c\u0435\u043d\u0442 \u0437\u0430 \u043f\u0440\u0435\u043c\u0438\u0435\u0440\u043d\u043e\u0442\u043e \u0438\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u0430 \u0415\u043c\u0431\u0438.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "\u0417\u0430\u043f\u0438\u0441\u0432\u0430\u043d\u0435", + "Save": "\u0417\u0430\u043f\u0430\u0437\u0432\u0430\u043d\u0435", + "Edit": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u043d\u0435", + "Download": "\u0418\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0435", + "Downloaded": "\u0418\u0437\u0442\u0435\u0433\u043b\u0435\u043d\u0438", + "Downloading": "\u0418\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0435", + "Advanced": "\u0420\u0430\u0437\u0448\u0438\u0440\u0435\u043d\u0438", + "Delete": "\u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435", + "HeaderDeleteItem": "Delete Item", + "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", + "Refresh": "\u041e\u043f\u0440\u0435\u0441\u043d\u044f\u0432\u0430\u043d\u0435", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043a\u044a\u043c \u043a\u043e\u043b\u0435\u043a\u0446\u0438\u044f", + "HeaderAddToCollection": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043a\u044a\u043c \u043a\u043e\u043b\u0435\u043a\u0446\u0438\u044f", + "NewCollection": "\u041d\u043e\u0432\u0430 \u043a\u043e\u043b\u0435\u043a\u0446\u0438\u044f", + "LabelCollection": "\u041a\u043e\u043b\u0435\u043a\u0446\u0438\u044f:", + "Help": "\u041f\u043e\u043c\u043e\u0449", + "LabelDisplayMode": "\u0420\u0435\u0436\u0438\u043c \u043d\u0430 \u043f\u043e\u043a\u0430\u0437\u0432\u0430\u043d\u0435:", + "Desktop": "\u0420\u0430\u0431\u043e\u0442\u0435\u043d \u043f\u043b\u043e\u0442", + "Mobile": "\u041c\u043e\u0431\u0438\u043b\u043d\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e", + "TV": "\u0422\u0435\u043b\u0435\u0432\u0438\u0437\u043e\u0440", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "\u0415\u0437\u0438\u043a \u043d\u0430 \u043f\u043e\u043a\u0430\u0437\u0432\u0430\u043d\u0435:", + "LabelDisplayLanguageHelp": "\u041f\u0440\u0435\u0432\u0435\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0415\u043c\u0431\u0438 \u0435 \u0442\u0435\u043a\u0443\u0449 \u043f\u0440\u043e\u0435\u043a\u0442.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "\u0422\u044a\u0440\u0441\u0435\u043d\u0435 \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0437\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u0438 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u0438", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "\u0422\u0435\u043c\u0430\u0442\u0438\u0447\u043d\u0438 \u043f\u0435\u0441\u043d\u0438", + "EnableBackdrops": "\u0424\u043e\u043d\u043e\u0432\u0435", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "\u0418\u043c\u0435:", + "NewCollectionNameExample": "\u041f\u0440\u0438\u043c\u0435\u0440: \u043a\u043e\u043b\u0435\u043a\u0446\u0438\u044f \u041c\u0435\u0436\u0434\u0443\u0437\u0432\u0435\u0437\u0434\u043d\u0438 \u0432\u043e\u0439\u043d\u0438", + "MessageItemsAdded": "Items added.", + "OptionNew": "\u041d\u043e\u0432...", + "LabelPlaylist": "\u0421\u043f\u0438\u0441\u044a\u043a:", + "AddToPlaylist": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043a\u044a\u043c \u0441\u043f\u0438\u0441\u044a\u043a", + "HeaderAddToPlaylist": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043a\u044a\u043c \u0441\u043f\u0438\u0441\u044a\u043a", + "Subtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u0438", + "LabelTheme": "\u041e\u0431\u043b\u0438\u043a:", + "LabelDashboardTheme": "\u041e\u0431\u043b\u0438\u043a \u043d\u0430 \u0441\u044a\u0440\u0432\u044a\u0440\u043d\u043e\u0442\u043e \u0442\u0430\u0431\u043b\u043e:", + "SearchForSubtitles": "\u0422\u044a\u0440\u0441\u0435\u043d\u0435 \u043d\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438", + "LabelLanguage": "\u0415\u0437\u0438\u043a:", + "Search": "\u0422\u044a\u0440\u0441\u0435\u043d\u0435", + "NoSubtitleSearchResultsFound": "\u041d\u044f\u043c\u0430 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438 \u0440\u0435\u0437\u0443\u043b\u0442\u0430\u0442\u0438.", + "File": "\u0424\u0430\u0439\u043b", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "\u041c\u043e\u0438\u0442\u0435 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438\u0442\u0435", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "\u041e\u043f\u0440\u0435\u0441\u043d\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u0438\u0442\u0435", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "\u0422\u044a\u0440\u0441\u0435\u043d\u0435 \u0437\u0430 \u043b\u0438\u0441\u0432\u0430\u0449\u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u0438", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "\u041e\u043f\u0438\u0442\u0430\u0439\u0442\u0435 \u043e\u0442\u043d\u043e\u0432\u043e", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "\u0414\u0438\u0441\u043a {0}", + "Unrated": "Unrated", + "Favorite": "\u0412 \u043b\u044e\u0431\u0438\u043c\u0438", + "Like": "\u0425\u0430\u0440\u0435\u0441\u0432\u0430\u043d\u0435", + "Dislike": "\u041d\u0435\u0445\u0430\u0440\u0435\u0441\u0432\u0430\u043d\u0435", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "\u041e\u0442\u0432\u0430\u0440\u044f\u043d\u0435", + "Play": "\u041f\u0443\u0441\u043a\u0430\u043d\u0435", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "\u041f\u0443\u0441\u043a\u0430\u043d\u0435 \u0432 \u0440\u0430\u0437\u0431\u044a\u0440\u043a\u0430\u043d \u0440\u0435\u0434", + "Identify": "\u0420\u0430\u0437\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0435", + "EditImages": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u0442\u0430", + "EditMetadata": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u0438\u0442\u0435", + "Convert": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0432\u0430\u043d\u0435", + "Sync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0430\u043d\u0435", + "InstantMix": "\u041f\u0443\u0441\u043a\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u0438", + "ViewAlbum": "\u041f\u0440\u0435\u0433\u043b\u0435\u0434 \u043d\u0430 \u0430\u043b\u0431\u0443\u043c\u0430", + "ViewArtist": "\u041f\u0440\u0435\u0433\u043b\u0435\u0434 \u043d\u0430 \u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u044f", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "\u041f\u0443\u0441\u043a\u0430\u043d\u0435 \u043d\u0430 \u0432\u0441\u0438\u0447\u043a\u043e \u043e\u0442 \u0442\u0443\u043a", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "\u041f\u0440\u043e\u0434\u044a\u043b\u0436\u0430\u0432\u0430\u043d\u0435 \u043e\u0442 {0}", + "RemoveFromPlaylist": "\u041f\u0440\u0435\u043c\u0430\u0445\u0432\u0430\u043d\u0435 \u043e\u0442 \u0441\u043f\u0438\u0441\u044a\u043a\u0430", + "RemoveFromCollection": "\u041f\u0440\u0435\u043c\u0430\u0445\u0432\u0430\u043d\u0435 \u043e\u0442 \u043a\u043e\u043b\u0435\u043a\u0446\u0438\u044f\u0442\u0430", + "Sort": "\u041f\u043e\u0434\u0440\u0435\u0436\u0434\u0430\u043d\u0435", + "Trailer": "\u0422\u0440\u0435\u0439\u043b\u044a\u0440", + "MarkPlayed": "\u041e\u0442\u0431\u0435\u043b\u044f\u0437\u0432\u0430\u043d\u0435 \u043a\u0430\u0442\u043e \u043f\u0443\u0441\u043a\u0430\u043d\u043e", + "MarkUnplayed": "\u041e\u0442\u0431\u0435\u043b\u044f\u0437\u0432\u0430\u043d\u0435 \u043a\u0430\u0442\u043e \u043d\u0435\u043f\u0443\u0441\u043a\u0430\u043d\u043e", + "GroupVersions": "\u0413\u0440\u0443\u043f\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438\u0442\u0435", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "\u0413\u0440\u0435\u0448\u043a\u0430", + "VoiceInput": "Voice Input", + "LabelContentType": "\u0422\u0438\u043f \u043d\u0430 \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435\u0442\u043e:", + "LabelPath": "\u041f\u044a\u0442:", + "Playlists": "\u0421\u043f\u0438\u0441\u044a\u0446\u0438", + "LabelTitle": "\u0417\u0430\u0433\u043b\u0430\u0432\u0438\u0435:", + "LabelOriginalTitle": "\u041e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u043d\u043e \u0437\u0430\u0433\u043b\u0430\u0432\u0438\u0435:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "\u0414\u0430\u0442\u0430 \u043d\u0430 \u0434\u043e\u0431\u0430\u0432\u044f\u043d\u0435:", + "DateAdded": "\u0414\u0430\u0442\u0430 \u043d\u0430 \u0434\u043e\u0431\u0430\u0432\u044f\u043d\u0435", + "DatePlayed": "\u0414\u0430\u0442\u0430 \u043d\u0430 \u043f\u0443\u0441\u043a\u0430\u043d\u0435", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "\u0421\u044a\u0441\u0442\u043e\u044f\u043d\u0438\u0435:", + "LabelArtists": "\u0418\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438:", + "LabelArtistsHelp": "\u041e\u0442\u0434\u0435\u043b\u0435\u0442\u0435 \u043d\u044f\u043a\u043e\u043b\u043a\u043e \u0441 ;", + "HeaderAlbumArtists": "\u0418\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 \u043d\u0430 \u0430\u043b\u0431\u0443\u043c\u0438", + "LabelAlbumArtists": "\u0418\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 \u043d\u0430 \u0430\u043b\u0431\u0443\u043c\u0430:", + "LabelAlbum": "\u0410\u043b\u0431\u0443\u043c:", + "Artists": "\u0418\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438", + "ImdbRating": "\u041e\u0446\u0435\u043d\u043a\u0430 \u0432 IMDb", + "CommunityRating": "\u041e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u0430 \u043e\u0449\u0435\u043d\u043a\u0430", + "LabelCommunityRating": "\u041e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u0430 \u043e\u0446\u0435\u043d\u043a\u0430", + "LabelCriticRating": "\u041e\u0446\u0435\u043d\u043a\u0430 \u043d\u0430 \u043a\u0440\u0438\u0442\u0438\u0446\u0438\u0442\u0435:", + "CriticRating": "\u041e\u0446\u0435\u043d\u043a\u0430 \u043d\u0430 \u043a\u0440\u0438\u0442\u0438\u0446\u0438\u0442\u0435", + "LabelWebsite": "\u0421\u0430\u0439\u0442:", + "LabelTagline": "Tagline:", + "LabelOverview": "\u041e\u0431\u043e\u0431\u0449\u0435\u043d\u0438\u0435:", + "LabelShortOverview": "\u041a\u0440\u0430\u0442\u043a\u043e \u043e\u0431\u043e\u0431\u0449\u0435\u043d\u0438\u0435:", + "LabelReleaseDate": "\u0414\u0430\u0442\u0430 \u043d\u0430 \u0438\u0437\u0434\u0430\u0432\u0430\u043d\u0435:", + "LabelYear": "\u0413\u043e\u0434\u0438\u043d\u0430:", + "LabelPlaceOfBirth": "\u0420\u043e\u0436\u0434\u0435\u043d\u043e \u043c\u044f\u0441\u0442\u043e:", + "Aired": "\u0418\u0437\u043b\u044a\u0447\u0435\u043d\u043e", + "LabelAirDays": "\u0414\u043d\u0438 \u043d\u0430 \u0438\u0437\u043b\u044a\u0447\u0432\u0430\u043d\u0435:", + "LabelAirTime": "\u0427\u0430\u0441 \u043d\u0430 \u0438\u0437\u043b\u044a\u0447\u0432\u0430\u043d\u0435:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "\u0420\u043e\u0434\u0438\u0442\u0435\u043b\u0441\u043a\u0430 \u043e\u0446\u0435\u043d\u043a\u0430:", + "LabelCustomRating": "\u041e\u0446\u0435\u043d\u043a\u0430 \u043f\u043e \u0438\u0437\u0431\u043e\u0440:", + "LabelOriginalAspectRatio": "\u041e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u043d\u043e \u0441\u044a\u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435:", + "Label3DFormat": "\u0422\u0440\u0438\u0438\u0437\u043c\u0435\u0440\u0435\u043d \u0444\u043e\u0440\u043c\u0430\u0442:", + "FormatValue": "\u0424\u043e\u0440\u043c\u0430\u0442: {0}", + "DownloadsValue": "{0} \u0438\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0438\u044f", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u043f\u043e\u043a\u0430\u0437\u0432\u0430\u043d\u0435", + "LabelDisplayOrder": "\u0420\u0435\u0434 \u043d\u0430 \u043f\u043e\u043a\u0430\u0437\u0432\u0430\u043d\u0435:", + "Display": "\u041f\u043e\u043a\u0430\u0437\u0432\u0430\u043d\u0435", + "Countries": "\u0414\u044a\u0440\u0436\u0430\u0432\u0438", + "Genres": "\u0416\u0430\u043d\u0440\u043e\u0432\u0435", + "Studios": "\u0421\u0442\u0443\u0434\u0438\u0430", + "Tags": "\u0415\u0442\u0438\u043a\u0435\u0442\u0438", + "HeaderMetadataSettings": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u0438\u0442\u0435", + "People": "\u0425\u043e\u0440\u0430", + "LabelMetadataDownloadLanguage": "\u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u043d \u0435\u0437\u0438\u043a \u043d\u0430 \u0441\u0432\u0430\u043b\u044f\u043d\u0435:", + "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", + "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", + "LabelCountry": "\u0414\u044a\u0440\u0436\u0430\u0432\u0430:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "\u041d\u043e\u043c\u0435\u0440 \u043d\u0430 \u0441\u0435\u0437\u043e\u043d\u0430:", + "LabelEpisodeNumber": "\u041d\u043e\u043c\u0435\u0440 \u043d\u0430 \u0435\u043f\u0438\u0437\u043e\u0434\u0430:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "\u0414\u0430\u0442\u0430 \u043d\u0430 \u0438\u0437\u0434\u0430\u0432\u0430\u043d\u0435", + "Continuing": "\u041f\u0440\u043e\u0434\u044a\u043b\u0436\u0430\u0432\u0430\u0449\u043e", + "Ended": "\u041f\u0440\u0438\u043a\u043b\u044e\u0447\u0438\u043b\u043e", + "HeaderEnabledFields": "\u0412\u043a\u043b\u044e\u0447\u0435\u043d\u0438 \u043f\u043e\u043b\u0435\u0442\u0430", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "\u0424\u043e\u043d\u043e\u0432\u0435", + "Images": "\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f", + "Runtime": "\u0412\u0440\u0435\u043c\u0435\u0442\u0440\u0430\u0435\u043d\u0435", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "\u0420\u043e\u0434\u0438\u0442\u0435\u043b\u0441\u043a\u0430 \u043e\u0446\u0435\u043d\u043a\u0430", + "PlayCount": "Play count", + "Name": "\u0418\u043c\u0435", + "Overview": "\u041e\u0431\u043e\u0431\u0449\u0435\u043d\u0438\u0435", + "LabelType": "\u0412\u0438\u0434:", + "LabelPersonRole": "\u0420\u043e\u043b\u044f:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "\u0410\u043a\u0442\u044c\u043e\u0440", + "Composer": "\u0421\u044a\u0447\u0438\u043d\u0438\u0442\u0435\u043b", + "Director": "\u0420\u0435\u0436\u0438\u0441\u044c\u043e\u0440", + "GuestStar": "\u0413\u043e\u0441\u0442\u0443\u0432\u0430\u0449\u0430 \u0437\u0432\u0435\u0437\u0434\u0430", + "Producer": "\u041f\u0440\u043e\u0434\u0443\u0446\u0435\u043d\u0442", + "Writer": "\u041f\u0438\u0441\u0430\u0442\u0435\u043b", + "MessageNoSyncJobsFound": "\u041d\u044f\u043c\u0430 \u0438\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0438\u044f. \u0421\u044a\u0437\u0434\u0430\u0439\u0442\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0447\u0440\u0435\u0437 \u043a\u043e\u043f\u0447\u0435\u0442\u0430\u0442\u0430 \u0437\u0430 \u0441\u0432\u0430\u043b\u044f\u043d\u0435.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "\u0418\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - \u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0435", + "ValueOneItem": "1 item", + "ValueOneSong": "1 \u043f\u0435\u0441\u0435\u043d", + "ValueSongCount": "{0} \u043f\u0435\u0441\u043d\u0438", + "ValueOneMovie": "1 \u0444\u0438\u043b\u043c", + "ValueMovieCount": "{0} \u0444\u0438\u043b\u043c\u0430", + "ValueOneSeries": "1 \u0441\u0435\u0440\u0438\u0430\u043b", + "ValueSeriesCount": "{0} \u0441\u0435\u0440\u0438\u0430\u043b\u0430", + "ValueOneEpisode": "1 \u0435\u043f\u0438\u0437\u043e\u0434", + "ValueEpisodeCount": "{0} \u0435\u043f\u0438\u0437\u043e\u0434\u0430", + "ValueOneGame": "1 \u0438\u0433\u0440\u0430", + "ValueGameCount": "{0} \u0438\u0433\u0440\u0438", + "ValueOneAlbum": "1 \u0430\u043b\u0431\u0443\u043c", + "ValueAlbumCount": "{0} \u0430\u043b\u0431\u0443\u043c\u0430", + "ValueOneMusicVideo": "1 \u043c\u0443\u0437\u0438\u043a\u0430\u043b\u0435\u043d \u043a\u043b\u0438\u043f", + "ValueMusicVideoCount": "{0} \u043c\u0443\u0437\u0438\u043a\u0430\u043b\u043d\u0438 \u043a\u043b\u0438\u043f\u0430", + "ValueMinutes": "{0} \u043c\u0438\u043d\u0443\u0442\u0438", + "Albums": "\u0410\u043b\u0431\u0443\u043c\u0438", + "Songs": "\u041f\u0435\u0441\u043d\u0438", + "Books": "\u041a\u043d\u0438\u0433\u0438", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "\u0421\u044a\u0440\u0432\u044a\u0440\u043d\u043e \u0438\u0437\u0434\u0430\u043d\u0438\u0435 \u0415\u043c\u0431\u0438 - {0} \u0441\u0435 \u043f\u0443\u0441\u043a\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e.", + "ServerNameIsShuttingDown": "\u0421\u044a\u0440\u0432\u044a\u0440\u043d\u043e \u0438\u0437\u0434\u0430\u043d\u0438\u0435 \u0415\u043c\u0431\u0438 - {0} \u0441\u0435 \u0438\u0437\u043a\u043b\u044e\u0447\u0432\u0430.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "\u041c\u043e\u043b\u044f, \u043f\u0443\u0441\u043d\u0435\u0442\u0435 \u0441\u044a\u0440\u0432\u044a\u0440\u0430 \u043e\u0442\u043d\u043e\u0432\u043e - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "\u0418\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0435...", + "HeaderSyncRequiresSub": "\u0418\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0435\u0442\u043e \u0438\u0437\u0438\u0441\u043a\u0432\u0430 \u0430\u043a\u0442\u0438\u0432\u0435\u043d \u0430\u0431\u043e\u043d\u0430\u043c\u0435\u043d\u0442 \u0437\u0430 \u043f\u0440\u0435\u043c\u0438\u0435\u0440\u043d\u043e\u0442\u043e \u0438\u0437\u0434\u0430\u043d\u0438\u0435.", + "LearnMore": "\u041d\u0430\u0443\u0447\u0435\u0442\u0435 \u043f\u043e\u0432\u0435\u0447\u0435", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e \u0441\u0432\u0430\u043b\u044f\u043d\u0435 \u043d\u0430 \u043d\u043e\u0432\u043e \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "\u0421\u043d\u0438\u043c\u043a\u0438 \u043d\u0430 \u0435\u043a\u0440\u0430\u043d\u0430", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "\u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u0442\u043e?", + "HeaderEditImages": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u0442\u0430", + "Settings": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "\u041d\u043e\u0432\u0438 \u0435\u043f\u0438\u0437\u043e\u0434\u0438", + "Episodes": "\u0415\u043f\u0438\u0437\u043e\u0434\u0438", + "HDPrograms": "\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0438 \u0441 \u0432\u0438\u0441\u043e\u043a\u0430 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u043d\u0430 \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442", + "Programs": "\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0438", + "LiveBroadcasts": "Live broadcasts", + "Premieres": "\u041f\u0440\u0435\u043c\u0438\u0435\u0440\u0438", + "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": "\u041d\u0430\u0443\u0447\u0435\u0442\u0435 \u043f\u043e\u0432\u0435\u0447\u0435", + "DeleteMedia": "\u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u043c\u0435\u0434\u0438\u044f\u0442\u0430", + "SeriesSettings": "Series settings", + "HeaderRecordingOptions": "Recording Options", + "CancelSeries": "Cancel series", + "DoNotRecord": "Do not record", + "HeaderSeriesOptions": "Series Options", + "LabelChannels": "Channels:", + "ChannelNameOnly": "Channel {0} only", + "Anytime": "Anytime", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "AllChannels": "All channels", + "LabelRecord": "Record:", + "NewEpisodesOnly": "\u0421\u0430\u043c\u043e \u043d\u043e\u0432\u0438 \u0435\u043f\u0438\u0437\u043e\u0434\u0438", + "AllEpisodes": "All episodes", + "LabelStartWhenPossible": "Start when possible:", + "LabelStopWhenPossible": "Stop when possible:", + "MinutesBefore": "\u043c\u0438\u043d\u0443\u0442\u0438 \u043f\u0440\u0435\u0434\u0438", + "MinutesAfter": "\u043c\u0438\u043d\u0443\u0442\u0438 \u0441\u043b\u0435\u0434", + "SkipEpisodesAlreadyInMyLibrary": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "LabelKeep:": "Keep:", + "UntilIDelete": "Until I delete", + "UntilSpaceNeeded": "Until space needed", + "Categories": "Categories", + "Sports": "\u0421\u043f\u043e\u0440\u0442\u043d\u0438", + "News": "\u041d\u043e\u0432\u0438\u043d\u0438", + "Movies": "\u0424\u0438\u043b\u043c\u0438", + "Kids": "Kids", + "EnableColorCodedBackgrounds": "Enable color coded backgrounds", + "SortChannelsBy": "Sort channels by:", + "RecentlyWatched": "\u0421\u043a\u043e\u0440\u043e \u0433\u043b\u0435\u0434\u0430\u043d\u0438", + "ChannelNumber": "Channel number", + "HeaderBenefitsEmbyPremiere": "\u041f\u0440\u0435\u0434\u0438\u043c\u0441\u0442\u0432\u0430 \u043d\u0430 \u043f\u0440\u0435\u043c\u0438\u0435\u0440\u043d\u043e\u0442\u043e \u0438\u0437\u0434\u0430\u043d\u0438\u0435", + "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Emby.", + "HeaderTryPlayback": "Try Playback", + "HowDidYouPay": "How did you pay?", + "IHaveEmbyPremiere": "\u0418\u043c\u0430\u043c \u043f\u0440\u0435\u043c\u0438\u0435\u0440\u043d\u043e \u0438\u0437\u0434\u0430\u043d\u0438\u0435", + "IPurchasedThisApp": "I purchased this app", + "ButtonRestorePreviousPurchase": "Restore Purchase", + "ButtonUnlockWithPurchase": "\u041e\u0442\u043a\u043b\u044e\u0447\u0432\u0430\u043d\u0435 \u0441 \u043f\u043e\u043a\u0443\u043f\u043a\u0430", + "ButtonUnlockPrice": "\u041e\u0442\u043a\u043b\u044e\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}", + "HeaderAlreadyPaid": "Already Paid?", + "ButtonPlayOneMinute": "Play One Minute", + "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", + "HeaderUnlockFeature": "\u041e\u0442\u043a\u043b\u044e\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0442\u0430", + "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": "\u041e\u0442\u043a\u0440\u0438\u0439\u0442\u0435 \u043f\u0440\u0435\u043c\u0438\u0435\u0440\u043d\u043e\u0442\u043e \u0438\u0437\u0434\u0430\u043d\u0438\u0435", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "\u0414\u043e\u0431\u0430\u0432\u0435\u043d\u043e \u043d\u0430 {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "\u0412 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442 \u0437\u0430 \u043f\u0440\u0435\u0445\u0432\u044a\u0440\u043b\u044f\u043d\u0435", + "SyncJobItemStatusSyncedMarkForRemoval": "\u041f\u0440\u0435\u043c\u0430\u0445\u0432\u0430\u043d\u0435 \u043e\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e", + "SyncJobItemStatusQueued": "\u0412 \u043e\u043f\u0430\u0448\u043a\u0430", + "SyncJobItemStatusConverting": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0432\u0430\u043d\u0435", + "SyncJobItemStatusTransferring": "\u041f\u0440\u0435\u0445\u0432\u044a\u0440\u043b\u044f\u043d\u0435", + "SyncJobItemStatusSynced": "\u0418\u0437\u0442\u0435\u0433\u043b\u0435\u043d\u043e", + "SyncJobItemStatusFailed": "\u041f\u0440\u043e\u0432\u0430\u043b\u0435\u043d\u043e", + "SyncJobItemStatusRemovedFromDevice": "\u041f\u0440\u0435\u043c\u0430\u0445\u043d\u0430\u0442\u043e", + "SyncJobItemStatusCancelled": "\u041e\u0442\u043a\u0430\u0437\u0430\u043d\u043e", + "Retry": "Retry", + "HeaderMyDevice": "\u041c\u043e\u0435\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e", + "Continue": "\u041f\u0440\u043e\u0434\u044a\u043b\u0436\u0430\u0432\u0430\u043d\u0435", + "ContinueInSecondsValue": "\u041f\u0440\u043e\u0434\u044a\u043b\u0436\u0430\u0432\u0430\u043d\u0435 \u0441\u043b\u0435\u0434 {0} \u0441\u0435\u043a\u0443\u043d\u0434\u0438.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "\u041f\u0443\u0441\u043a\u0430\u043d\u0435 \u043d\u0430", + "Quality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e", + "Auto": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "\u041c\u043e\u044f\u0442\u0430 \u043c\u0435\u0434\u0438\u044f", + "HeaderMyMediaSmall": "\u041c\u043e\u044f\u0442\u0430 \u043c\u0435\u0434\u0438\u044f (\u043c\u0430\u043b\u044a\u043a)", + "LatestFromLibrary": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438 {0}", + "ContinueWatching": "\u041f\u0440\u043e\u0434\u044a\u043b\u0436\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u0433\u043b\u0435\u0434\u0430\u043d\u0435\u0442\u043e", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "\u041f\u0440\u043e\u0434\u044a\u043b\u0436\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u0433\u043b\u0435\u0434\u0430\u043d\u0435\u0442\u043e", + "HeaderContinueListening": "\u041f\u0440\u043e\u0434\u044a\u043b\u0436\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u0441\u043b\u0443\u0448\u0430\u043d\u0435\u0442\u043e", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438 \u0437\u0430\u043f\u0438\u0441\u0438", + "LabelSyncTo": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0430\u043d\u0435 \u043a\u044a\u043c:", + "LabelConvertTo": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0432\u0430\u043d\u0435 \u0432:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "\u0412\u0435\u0440\u0441\u0438\u044f:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "\u0421\u043b\u0435\u0434\u0432\u0430", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "\u0420\u0430\u0437\u0434\u0435\u043b {0} \u043d\u0430 \u043d\u0430\u0447\u0430\u043b\u043d\u0438\u044f \u0435\u043a\u0440\u0430\u043d:", + "SettingsSaved": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u0441\u0430 \u0437\u0430\u043f\u0430\u0437\u0435\u043d\u0438.", + "None": "\u041d\u0438\u0449\u043e", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "\u041d\u0430\u0447\u0430\u043b\u043e", + "Favorites": "\u041b\u044e\u0431\u0438\u043c\u0438", + "HeaderHomeScreen": "\u041d\u0430\u0447\u0430\u043b\u0435\u043d \u0435\u043a\u0440\u0430\u043d", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "\u041f\u043e\u0434\u0440\u0435\u0434\u0431\u0430 \u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0442\u0430", + "HideWatchedContentFromLatestMedia": "\u0421\u043a\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0433\u043b\u0435\u0434\u0430\u043d\u043e\u0442\u043e \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435 \u043e\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u043c\u0435\u0434\u0438\u044f", + "HeaderOnNow": "\u041d\u0430 \u0436\u0438\u0432\u043e \u0441\u0435\u0433\u0430", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "\u0421\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a", + "Suggestions": "\u041f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f", + "HeaderFavoriteCollections": "\u041b\u044e\u0431\u0438\u043c\u0438 \u043a\u043e\u043b\u0435\u043a\u0446\u0438\u0438", + "HeaderFavoritePlaylists": "\u041b\u044e\u0431\u0438\u043c\u0438 \u0441\u043f\u0438\u0441\u044a\u0446\u0438", + "Collections": "\u041a\u043e\u043b\u0435\u043a\u0446\u0438\u0438", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "\u041f\u0440\u0435\u0434\u0430\u0432\u0430\u043d\u0438\u044f", + "HeaderLibraryFolders": "\u041f\u0430\u043f\u043a\u0438 \u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0442\u0430", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "\u0422\u0435\u043b\u0435\u0432\u0438\u0437\u0438\u044f \u043d\u0430 \u0436\u0438\u0432\u043e", + "Schedule": "\u0420\u0430\u0437\u043f\u0438\u0441\u0430\u043d\u0438\u0435", + "Recordings": "Recordings", + "MarkWatched": "\u041e\u0442\u0431\u0435\u043b\u044f\u0437\u0432\u0430\u043d\u0435 \u043a\u0430\u0442\u043e \u0438\u0437\u0433\u043b\u0435\u0434\u0430\u043d\u043e", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "\u0421\u043c\u0435\u0442\u043a\u0430\u0442\u0430 \u0432 \u0415\u043c\u0431\u0438 \u0435 \u043f\u0440\u0435\u043c\u0430\u0445\u043d\u0430\u0442\u0430", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "\u041f\u043e\u043a\u0430\u043d\u0430\u0442\u0430 \u0435 \u0438\u0437\u043f\u0440\u0430\u0442\u0435\u043d\u0430", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "\u0421\u043c\u0435\u0442\u043a\u0430\u0442\u0430 \u0432 \u0415\u043c\u0431\u0438 \u0435 \u0434\u043e\u0431\u0430\u0432\u0435\u043d\u0430", + "LabelSubtitlePlaybackMode": "\u0420\u0435\u0436\u0438\u043c \u043d\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438\u0442\u0435:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "\u0411\u0435\u0437 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438", + "Default": "\u041f\u043e \u043f\u043e\u0434\u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043d\u0435", + "Absolute": "Absolute", + "Smart": "\u0423\u043c\u043d\u0438", + "Small": "\u041c\u0430\u043b\u044a\u043a", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "\u0413\u043e\u043b\u044f\u043c", + "ExtraLarge": "\u041c\u043d\u043e\u0433\u043e \u0433\u043e\u043b\u044f\u043c", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438\u0442\u0435", + "HeaderSubtitleAppearance": "\u041e\u0431\u043b\u0438\u043a \u043d\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438\u0442\u0435", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "\u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u043d \u0435\u0437\u0438\u043a \u043d\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438\u0442\u0435:", + "LabelTextSize": "\u0420\u0430\u0437\u043c\u0435\u0440 \u043d\u0430 \u0442\u0435\u043a\u0441\u0442\u0430:", + "TheseSettingsAffectSubtitlesOnThisDevice": "\u0422\u0435\u0437\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u043e\u043c\u0435\u043d\u044f\u0442 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438\u0442\u0435 \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u043e\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e", + "LabelDropShadow": "\u0421\u044f\u043d\u043a\u0430:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "\u0428\u0440\u0438\u0444\u0442:", + "LabelTextColor": "\u0426\u0432\u044f\u0442 \u043d\u0430 \u0442\u0435\u043a\u0441\u0442\u0430:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "\u041d\u043e\u0440\u043c\u0430\u043b\u0435\u043d", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "\u0421\u043a\u0440\u0438\u0432\u0430\u043d\u0435", + "HeaderStartNow": "\u041f\u0443\u0441\u043a\u0430\u043d\u0435 \u0432\u0435\u0434\u043d\u0430\u0433\u0430", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "\u0421\u043b\u0435\u0434\u0432\u0430\u0449\u0438\u044f\u0442 \u0435\u043f\u0438\u0437\u043e\u0434 \u0449\u0435 \u0441\u0435 \u043f\u0443\u0441\u043d\u0435 \u0441\u043b\u0435\u0434 {0}", + "HeaderSecondsValue": "{0} \u0441\u0435\u043a\u0443\u043d\u0434\u0438", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "\u041f\u0443\u0441\u043d\u0435\u0442\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0442\u0443\u043a \u0438\u043b\u0438 \u0449\u0440\u0430\u043a\u043d\u0435\u0442\u0435 \u0437\u0430 \u0440\u0430\u0437\u0433\u043b\u0435\u0436\u0434\u0430\u043d\u0435.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "\u0420\u0430\u0437\u0433\u043b\u0435\u0436\u0434\u0430\u043d\u0435", + "HeaderUploadImage": "\u041a\u0430\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", + "HeaderAddUpdateImage": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435\/\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", + "LabelImageType": "\u0412\u0438\u0434 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435:", + "Upload": "\u041a\u0430\u0447\u0432\u0430\u043d\u0435", + "Primary": "\u0413\u043b\u0430\u0432\u043d\u043e", + "Art": "\u041a\u0430\u0440\u0442\u0438\u043d\u0430", + "Backdrop": "\u0424\u043e\u043d", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "\u0414\u0438\u0441\u043a", + "Logo": "\u041b\u043e\u0433\u043e\u0442\u0438\u043f", + "Menu": "\u041c\u0435\u043d\u044e", + "Screenshot": "\u0421\u043d\u0438\u043c\u043a\u0430 \u043d\u0430 \u0435\u043a\u0440\u0430\u043d\u0430", + "Thumb": "\u041c\u0438\u043d\u0438\u0430\u0442\u044e\u0440\u0430", + "ValueSeconds": "{0} \u0441\u0435\u043a\u0443\u043d\u0434\u0438", + "HeaderAudioSettings": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u0437\u0432\u0443\u043a\u0430", + "LabelAudioLanguagePreference": "\u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u043d \u0435\u0437\u0438\u043a \u043d\u0430 \u0437\u0432\u0443\u043a\u0430:", + "LabelPlayDefaultAudioTrack": "\u0414\u0430 \u0441\u0435 \u043f\u0443\u0441\u043a\u0430 \u043f\u044a\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u043d\u0430\u0442\u0430 \u0437\u0432\u0443\u043a\u043e\u0432\u0430 \u043f\u044a\u0442\u0435\u0447\u043a\u0430 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0435\u0437\u0438\u043a\u0430", + "HeaderVideoQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430 \u0432\u0438\u0434\u0435\u043e\u0442\u043e", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e \u043f\u0443\u0441\u043a\u0430\u043d\u0435 \u043d\u0430 \u0441\u043b\u0435\u0434\u0432\u0430\u0449\u0438\u044f \u0435\u043f\u0438\u0437\u043e\u0434", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "\u0412\u043a\u043b\u044e\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 \u0440\u0435\u0436\u0438\u043c \"\u041a\u0438\u043d\u043e\u0441\u0430\u043b\u043e\u043d\"", + "LabelInternetQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u043d\u0430\u0442\u0430 \u0432\u0440\u044a\u0437\u043a\u0430:", + "HeaderMusicQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430 \u043c\u0443\u0437\u0438\u043a\u0430\u0442\u0430", + "LabelHomeNetworkQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430 \u0434\u043e\u043c\u0430\u0448\u043d\u0430\u0442\u0430 \u043c\u0440\u0435\u0436\u0430:", + "HeaderLatestMedia": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438 \u043c\u0435\u0434\u0438\u0438", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u0438 \u0441\u0435\u0437\u043e\u043d\u043d\u0438 \u043e\u0431\u043b\u0438\u0446\u0438", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e (\u0441\u043f\u043e\u0440\u0435\u0434 \u0435\u0437\u0438\u043a\u0430)", + "LabelDateTimeLocale": "\u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430 \u0434\u0430\u0442\u0430 \u0438 \u0447\u0430\u0441:", + "DirectorValue": "\u0420\u0435\u0436\u0438\u0441\u044c\u043e\u0440: {0}", + "DirectorsValue": "\u0420\u0435\u0436\u0438\u0441\u044c\u043e\u0440\u0438: {0}", + "GenreValue": "\u0416\u0430\u043d\u0440: {0}", + "GenresValue": "\u0416\u0430\u043d\u0440\u043e\u0432\u0435: {0}", + "LinksValue": "\u041f\u0440\u0435\u043f\u0440\u0430\u0442\u043a\u0438: {0}", + "TagsValue": "\u0415\u0442\u0438\u043a\u0435\u0442\u0438: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u0438:", + "Off": "\u0418\u0437\u043a\u043b\u044e\u0447\u0435\u043d\u043e", + "ShowTitle": "\u041f\u043e\u043a\u0430\u0437\u0432\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0433\u043b\u0430\u0432\u0438\u0435\u0442\u043e", + "ShowYear": "\u041f\u043e\u043a\u0430\u0437\u0432\u0430\u043d\u0435 \u043d\u0430 \u0433\u043e\u0434\u0438\u043d\u0430\u0442\u0430", + "Filters": "\u0424\u0438\u043b\u0442\u0440\u0438", + "Unplayed": "\u041d\u0435\u043f\u0443\u0441\u043a\u0430\u043d\u043e", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "\u0412\u043e\u0434\u043e\u0440\u0430\u0432\u043d\u043e", + "Vertical": "\u041e\u0442\u0432\u0435\u0441\u043d\u043e", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "\u0422\u0440\u0435\u0439\u043b\u044a\u0440\u0438", + "Extras": "\u0415\u043a\u0441\u0442\u0440\u0438", + "ThemeSongs": "\u0424\u043e\u043d\u043e\u0432\u0438 \u043f\u0435\u0441\u043d\u0438", + "ThemeVideos": "\u0424\u043e\u043d\u043e\u0432\u0438 \u0432\u0438\u0434\u0435\u043e\u043a\u043b\u0438\u043f\u043e\u0432\u0435", + "HeaderFavoriteMovies": "\u041b\u044e\u0431\u0438\u043c\u0438 \u0444\u0438\u043b\u043c\u0438", + "HeaderFavoriteShows": "\u041b\u044e\u0431\u0438\u043c\u0438 \u043f\u0440\u0435\u0434\u0430\u0432\u0430\u043d\u0438\u044f", + "HeaderFavoriteEpisodes": "\u041b\u044e\u0431\u0438\u043c\u0438 \u0435\u043f\u0438\u0437\u043e\u0434\u0438", + "HeaderFavoriteVideos": "\u041b\u044e\u0431\u0438\u043c\u0438 \u043a\u043b\u0438\u043f\u043e\u0432\u0435", + "HeaderFavoriteGames": "\u041b\u044e\u0431\u0438\u043c\u0438 \u0438\u0433\u0440\u0438", + "HeaderFavoriteArtists": "\u041b\u044e\u0431\u0438\u043c\u0438 \u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438", + "HeaderFavoriteAlbums": "\u041b\u044e\u0431\u0438\u043c\u0438 \u0430\u043b\u0431\u0443\u043c\u0438", + "HeaderFavoriteSongs": "\u041b\u044e\u0431\u0438\u043c\u0438 \u043f\u0435\u0441\u043d\u0438", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "\u0426\u0432\u0435\u0442\u043e\u0432\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/ca.json b/src/bower_components/emby-webcomponents/strings/ca.json index fe25dd0c36..67f9fba111 100644 --- a/src/bower_components/emby-webcomponents/strings/ca.json +++ b/src/bower_components/emby-webcomponents/strings/ca.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accepta", - "AccessRestrictedTryAgainLater": "L'accés està restringit actualment. Intenta-ho de nou més tard si et plau.", - "Actor": "Actor", - "Add": "Afegeix", - "AddToCollection": "Afegeix a col·lecció", - "AddToPlayQueue": "Afegeix a la llista de reproducció", - "AddToPlaylist": "Afegeix a la llista de reproducció", - "AddedOnValue": "Added {0}", - "Advanced": "Avançat", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "Tots els canals", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Tots els episodis", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Reprodueix sempre amb subtítols", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Cap a les {0}", - "Art": "Art", - "Artists": "Artistes", - "AsManyAsPossible": "Tants com sigui possible", - "Ascending": "Ascending", - "AspectRatio": "Relació d'aspecte", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "Nou", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Descarrega nou contingut automàticament", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Millor ajustament", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Cancel·la", - "ButtonGotIt": "Entesos", - "ButtonOk": "D'acord", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Reiniciar", - "ButtonRestorePreviousPurchase": "Restaura Compra", - "ButtonTryAgain": "Intenta-ho de nou", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel·la descàrrega", - "CancelRecording": "Cancel·la enregistrament", - "CancelSeries": "Cancel·la sèrie", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sincronitza els teus mitjans amb el núvol per a copiar, arxivar i convertir fàcilment.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Compositor", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Esborrar imatge?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirma supressió", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connecta", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continua", - "ContinueInSecondsValue": "Continua en {0} segons", - "ContinueWatching": "Continue watching", - "Continuing": "Continuant", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Països", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Dies", - "Default": "Default", - "DefaultErrorMessage": "Hi ha hagut un error processant la petició. Intenta-ho més tard si et plau.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Esborra", - "DeleteMedia": "Esborra", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Escriptori", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Desconnecta", - "Dislike": "No m'agrada", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Mostra també els episodis que no tingui a les temporades", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Selecciona el tipus de pantalla en el que tens Jellyfin funcionant.", - "DoNotRecord": "No enregistris", - "Down": "Avall", - "Download": "Descarrega", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Descarregat", - "Downloading": "Descarregant", - "DownloadingDots": "Descarregant...", - "Downloads": "Descàrregues", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Programa enregistraments de TV en directe individuals, de sèries i molt més amb Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edita", - "EditImages": "Edita imatges", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edita subtítols", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Habilitar mode cinema", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Habilita la vista de mirall", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Acabades", - "EndsAtValue": "Acabaria a les {0}", - "Episodes": "Episodis", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorit", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "Fitxer", - "Fill": "Omplir", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Divendres", - "GenreValue": "Genre: {0}", - "Genres": "Gèneres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Artista convidat", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "Programes HD", - "HeaderActiveRecordings": "Enregistraments Actius", - "HeaderAddToCollection": "Afegir a Col·lecció", - "HeaderAddToPlaylist": "Afegir a la llista de reproducció", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Obtenir Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel·lar Enregistrament", - "HeaderCancelSeries": "Cancel·lar Sèries", - "HeaderCinemaMode": "Mode Cinema", - "HeaderCloudSync": "Sincronitzar amb el Núvol", - "HeaderConfirmRecordingCancellation": "Confirmar Cancel·lació de l'Enregistrament", - "HeaderContinueListening": "Continua Escoltant", - "HeaderContinueWatching": "Continua Veient", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Esborrar Ítem", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Opcions de Visualització", - "HeaderDownloadSettings": "Preferències de descàrregues", - "HeaderEditImages": "Edita Imatges", - "HeaderEnabledFields": "Camps Habilitats", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "Identificadors externs:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Llistes de Reproducció Preferides", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Pàgina d'Inici", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Continuar Enregistrant", - "HeaderKeepSeries": "Mantenir Sèries", - "HeaderLatestChannelItems": "Darrers ítems del canal", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Novetats a {0}", - "HeaderLatestMedia": "Darrers MItjans", - "HeaderLatestRecordings": "Darrers Enregistraments", - "HeaderLearnMore": "Saber-ne Més", - "HeaderLibraryFolders": "Directoris de la Llibreria", - "HeaderLibraryOrder": "Ordre de la llibreria", - "HeaderMetadataSettings": "Preferències de Metadades", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "El meu dispositiu", - "HeaderMyDownloads": "Les meves descàrregues", - "HeaderMyMedia": "Els meus mitjans", - "HeaderMyMediaSmall": "Els meus mitjans (petit)", - "HeaderNewRecording": "Nou Enregistrament", - "HeaderNextEpisodePlayingInValue": "Reproduint proper episodi en {0}", - "HeaderNextUp": "A continuació", - "HeaderNextVideoPlayingInValue": "Reproduint proper vídeo en {0}", - "HeaderOfflineDownloads": "Mitjans Sense Connexió", - "HeaderOfflineDownloadsDescription": "Descarrega mitjans als teus dispositius per a un fàcil ús fora de línia.", - "HeaderOnNow": "En Directe Ara", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Error de Reproducció", - "HeaderRecordingOptions": "Opcions d'Enregistrament", - "HeaderRemoteControl": "Control Remot", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Digues alguna cosa com...", - "HeaderSecondsValue": "{0} segons", - "HeaderSelectDate": "Seleccionar Data", - "HeaderSeriesOptions": "Opcions de Sèries", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Començar Ara", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Apariència de subtítols", - "HeaderSubtitleSettings": "Preferències de subtítols", - "HeaderSyncRequiresSub": "Descarregar requereix una subscripció activa d'Jellyfin Premiere.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Esperant Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "Has dit...", - "Help": "Ajuda", - "Hide": "Amaga", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identifica", - "Images": "Imatges", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Instal·lant {0}", - "InstantMix": "Mescla instantània", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} ítems", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Mantingues al dispositiu", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Àlbum:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artistes:", - "LabelArtistsHelp": "Separa'n varis emprant ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Data de naixement:", - "LabelBirthYear": "Any de naixement:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Canals:", - "LabelCollection": "Col·lecció:", - "LabelCommunityRating": "Valoració de la comunitat:", - "LabelContentType": "Tipus de contingut:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "País:", - "LabelCriticRating": "Valoració crítica:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Tema del tauler de control del servidor:", - "LabelDateAdded": "Data afegit:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Data de defunció:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc:", - "LabelDisplayLanguage": "Idioma de visualització:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Ordre de visualització:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "Identificador {0}:", - "LabelEmailAddress": "Correu electrònic:", - "LabelEndDate": "Data de finalització:", - "LabelEpisodeNumber": "Episodi:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Secció {0} de la pàgina d'inici:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Mantingues fins a:", - "LabelLanguage": "Idioma:", - "LabelLockItemToPreventChanges": "Bloca aquest ítem per evitar canvis futurs", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Idioma preferit de descàrrega:", - "LabelName": "Nom:", - "LabelNumber": "Nombre:", - "LabelOriginalAspectRatio": "Relació d'aspecte original:", - "LabelOriginalTitle": "Títol original:", - "LabelOverview": "Sinopsi:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Directori:", - "LabelPersonRole": "Rol:", - "LabelPersonRoleHelp": "Exemple: Conductor de camió de gelats", - "LabelPlaceOfBirth": "Lloc de naixement:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Llista de rep.:", - "LabelPreferredSubtitleLanguage": "Idioma preferit de subtítols:", - "LabelProfile": "Perfil:", - "LabelQuality": "Qualitat:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Enregistra:", - "LabelRefreshMode": "Mode de refresc:", - "LabelReleaseDate": "Data de publicació:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Salva pantalla:", - "LabelSeasonNumber": "Temporada:", - "LabelSelectFolderGroups": "Agrupa automàticament el contingut de les següents carpetes en col·leccions com Pel·lícules, Música i TV:", - "LabelSelectFolderGroupsHelp": "Les carpetes desmarcades serán mostrades individualment en la seva pròpia vista.", - "LabelShortOverview": "Sinopsi curta:", - "LabelSkin": "Aspecte:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Títol d'endreçat:", - "LabelSoundEffects": "Efectes de so:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Inicia quan sigui possible:", - "LabelStatus": "Estat:", - "LabelStopWhenPossible": "Atura quan sigui possible:", - "LabelSubtitlePlaybackMode": "Mode de subtítol:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sincronitza a:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Tema:", - "LabelTitle": "Títol:", - "LabelTrackNumber": "Pista:", - "LabelType": "Tipus:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Any:", - "Large": "Large", - "LatestFromLibrary": "Novetats a {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "M'agrada", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Directe", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requereix una subscripció d'Jellyfin Premiere activa", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Marca com a reproduït", - "MarkUnplayed": "Marca com a no reproduït", - "MarkWatched": "Marca com a vist", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Estàs segur que vols eliminar aquest fitxer de subtítols?", - "MessageConfirmRecordingCancellation": "Estàs segur que vols cancel·lar aquest enregistrament?", - "MessageDownloadQueued": "Descàrrega encuada.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Ítem desat.", - "MessageItemsAdded": "Ítems afegits.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No s'han trobat descàrregues sense connexió. Descarrega mitjans per reproduir sense connexió emprant els botons de \"Descarrega\" que trobaràs per tota l'app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No s'han trobat descàrregues. Crea noves tasques de descàrrega emprant els botons de \"Descarrega\" que trobaràs per tota l'app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "Si tens una subscripció activa d'Jellyfin Premiere assegura't que l'has configurat al teu tauler de control de l'Jellyfin Server, on pots accedir clicant a l'opció d'Jellyfin Premiere al menú principal.", - "MessageUnlockAppWithPurchaseOrSupporter": "Activa aquesta funcionalitat amb un únic pagament, o amb una subscripció activa d'Jellyfin Premiere.", - "MessageUnlockAppWithSupporter": "Activa aquesta funcionalitat amb una subscripció activa d'Jellyfin Premiere.", - "MessageWeDidntRecognizeCommand": "Ho sentim, no reconeixem aquesta comanda.", - "MinutesAfter": "minuts després", - "MinutesBefore": "minuts abans", - "Mobile": "Mòbil / Tauleta", - "Monday": "Dilluns", - "More": "Més", - "MoveLeft": "Moure a l'esquerra", - "MoveRight": "Moure a la dreta", - "Movies": "Movies", - "MySubtitles": "Els meus subtítols", - "Name": "Nom", - "NewCollection": "Nova Col·lecció", - "NewCollectionHelp": "Les col·leccions et permeten crear agrupacions personalitzades de pel·lícules i altres continguts.", - "NewCollectionNameExample": "Exemple: Col·leció Star Wars", - "NewEpisodes": "Nous episodis", - "NewEpisodesOnly": "Només nous episodis", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No s'han trobat ítems.", - "NoSubtitleSearchResultsFound": "No s'han trobat resultats.", - "NoSubtitles": "Sense subtítols", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "Cap", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Només subtítols forçats", - "OnlyForcedSubtitlesHelp": "Només es carregaran aquells subtítols marcats com a forçats.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Obre", - "OptionNew": "Nou...", - "Original": "Original", - "OriginalAirDateValue": "Data original d'emissió: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "Instal·lació {0} cancel·lada.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Valoració Parental", - "People": "Gent", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Reprodueix", - "PlayAllFromHere": "Reprodueix tots des d'aquí", - "PlayCount": "Play count", - "PlayFromBeginning": "Reprodueix des de l'inici", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Reproduït", - "Playlists": "Llistes de reproducció", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Reinicia el Servidor d'Jellyfin si et plau - {0}.", - "PleaseSelectDeviceToSyncTo": "Selecciona el dispositiu on ho vulguis descarregar.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Première", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Productor", - "ProductionLocations": "Production locations", - "Programs": "Programes", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Qualitat", - "QueueAllFromHere": "Afegeix tots a la cua des d'aquí", - "Raised": "Raised", - "RecentlyWatched": "Reproduït recentment", - "Record": "Grava", - "RecordSeries": "Enregistra la sèrie", - "RecordingCancelled": "Enregistrament cancel·lat.", - "RecordingScheduled": "Enregistrament programat.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresca", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresca metadades", - "RefreshQueued": "Actualització encuada.", - "Reject": "Rebutja", - "ReleaseDate": "Data de publicació", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Elimina de la col·lecció", - "RemoveFromPlaylist": "Esborra de la llista de reproducció", - "RemovingFromDevice": "Eliminant del dispositiu", - "Repeat": "Repeteix", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repetir episodis", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Reemplaça totes les metadades", - "ReplaceExistingImages": "Reemplaça imatges existents", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Reprodueix des de {0}", - "Retry": "Reintenta", - "RunAtStartup": "Arrenca en iniciar", - "Runtime": "Runtime", - "Saturday": "Dissabte", - "Save": "Desa", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Captures de pantalla", - "Search": "Cerca", - "SearchForCollectionInternetMetadata": "Cerca a internet artwork i metadades", - "SearchForMissingMetadata": "Cerca metadades perdudes", - "SearchForSubtitles": "Cerca Subtítols", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Sèrie cancel·lada.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Enregistrament de la sèrie programat.", - "SeriesSettings": "Preferències de la sèrie", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "El Servidor Jellyfin necessita ser actualitzat. Per descarregar la darrera versió, si et plau, visita {0}", - "Settings": "Preferències", - "SettingsSaved": "Preferències desades.", - "Share": "Comparteix", - "ShowIndicatorsFor": "Mostra indicadors per a:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Aleatori", - "SkipEpisodesAlreadyInMyLibrary": "No enregistris episodis que ja estan a la meva biblioteca", - "SkipEpisodesAlreadyInMyLibraryHelp": "Els episodis es compararan emprant la temporada i el nombre d'episodi quan siguin disponibles.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Nom per endreçar:", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Estudis", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Format de subtítol no suportat", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtítols", - "Suggestions": "Suggerències", - "Sunday": "Diumenge", - "Sync": "Sincronitza", - "SyncJobItemStatusCancelled": "Cancel·lat", - "SyncJobItemStatusConverting": "Convertint", - "SyncJobItemStatusFailed": "Fallit", - "SyncJobItemStatusQueued": "Encuat", - "SyncJobItemStatusReadyToTransfer": "Llest per transferir", - "SyncJobItemStatusRemovedFromDevice": "Eliminat del dispositiu", - "SyncJobItemStatusSynced": "Descarregat", - "SyncJobItemStatusSyncedMarkForRemoval": "Eliminant del dispositiu", - "SyncJobItemStatusTransferring": "Transferint", - "SyncUnwatchedVideosOnly": "Descarrega només els vídeos no vists", - "SyncUnwatchedVideosOnlyHelp": "Només els vídeos no vists seran descarregats, i els vídeos seran eliminats del dispositiu un cop s'hagin vist.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Etiquetes", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "Aquestes preferències afecten els subtítols d'aquest dispositiu", - "Thumb": "Thumb", - "Thursday": "Dijous", - "TrackCount": "{0} pistes", - "Trailer": "Tràiler", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Prova el Multi-Select", - "TryMultiSelectMessage": "Per editar múltiples mitjans multimèdia simplement fes clic i mantingues premut sobre qualsevol cartell i després selecciona els ítems que vulguis gestionar. Prova-ho!", - "Tuesday": "Dimarts", - "Uniform": "Uniform", - "UnlockGuide": "Guia de desbloqueig", - "Unplayed": "Unplayed", - "Unrated": "Sense valorar", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Amunt", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodis", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} vídeos musicals", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 vídeo musical", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Especial - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "Veure àlbum", - "ViewArtist": "Veure artista", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Vists", - "Wednesday": "Dimecres", - "WifiRequiredToDownload": "Es requereix una connexió Wifi per continuar descarregant.", - "Writer": "Escriptor", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "Activa aquesta funcionalitat amb un \u00fanic pagament, o amb una subscripci\u00f3 activa d'Emby Premiere.", + "MessageUnlockAppWithSupporter": "Activa aquesta funcionalitat amb una subscripci\u00f3 activa d'Emby Premiere.", + "MessageToValidateSupporter": "Si tens una subscripci\u00f3 activa d'Emby Premiere assegura't que l'has configurat al teu tauler de control de l'Emby Server, on pots accedir clicant a l'opci\u00f3 d'Emby Premiere al men\u00fa principal.", + "ValueSpecialEpisodeName": "Especial - {0}", + "Share": "Comparteix", + "Add": "Afegeix", + "ServerUpdateNeeded": "El Servidor Emby necessita ser actualitzat. Per descarregar la darrera versi\u00f3, si et plau, visita {0}", + "LiveTvRequiresUnlock": "Live TV requereix una subscripci\u00f3 d'Emby Premiere activa", + "AttributeNew": "Nou", + "Premiere": "Premi\u00e8re", + "Live": "Directe", + "Repeat": "Repeteix", + "TrackCount": "{0} pistes", + "ItemCount": "{0} \u00edtems", + "OriginalAirDateValue": "Data original d'emissi\u00f3: {0}", + "EndsAtValue": "Acabaria a les {0}", + "HeaderSelectDate": "Seleccionar Data", + "Watched": "Vists", + "AirDate": "Air date", + "Played": "Reprodu\u00eft", + "ButtonOk": "D'acord", + "ButtonCancel": "Cancel\u00b7la", + "AccessRestrictedTryAgainLater": "L'acc\u00e9s est\u00e0 restringit actualment. Intenta-ho de nou m\u00e9s tard si et plau.", + "ButtonGotIt": "Entesos", + "ButtonRestart": "Reiniciar", + "RecordingCancelled": "Enregistrament cancel\u00b7lat.", + "SeriesCancelled": "S\u00e8rie cancel\u00b7lada.", + "RecordingScheduled": "Enregistrament programat.", + "SeriesRecordingScheduled": "Enregistrament de la s\u00e8rie programat.", + "HeaderNewRecording": "Nou Enregistrament", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Diumenge", + "Monday": "Dilluns", + "Tuesday": "Dimarts", + "Wednesday": "Dimecres", + "Thursday": "Dijous", + "Friday": "Divendres", + "Saturday": "Dissabte", + "Days": "Dies", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Enregistra la s\u00e8rie", + "HeaderCinemaMode": "Mode Cinema", + "HeaderCloudSync": "Sincronitzar amb el N\u00favol", + "Downloads": "Desc\u00e0rregues", + "HeaderMyDownloads": "Les meves desc\u00e0rregues", + "HeaderOfflineDownloads": "Mitjans Sense Connexi\u00f3", + "HeaderOfflineDownloadsDescription": "Descarrega mitjans als teus dispositius per a un f\u00e0cil \u00fas fora de l\u00ednia.", + "CloudSyncFeatureDescription": "Sincronitza els teus mitjans amb el n\u00favol per a copiar, arxivar i convertir f\u00e0cilment.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Programa enregistraments de TV en directe individuals, de s\u00e8ries i molt m\u00e9s amb Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Obtenir Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "LabelEmailAddress": "Correu electr\u00f2nic:", + "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": "Grava", + "Save": "Desa", + "Edit": "Edita", + "Download": "Descarrega", + "Downloaded": "Descarregat", + "Downloading": "Descarregant", + "Advanced": "Avan\u00e7at", + "Delete": "Esborra", + "HeaderDeleteItem": "Esborrar \u00cdtem", + "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", + "Refresh": "Refresca", + "RefreshQueued": "Actualitzaci\u00f3 encuada.", + "AddToCollection": "Afegeix a col\u00b7lecci\u00f3", + "HeaderAddToCollection": "Afegir a Col\u00b7lecci\u00f3", + "NewCollection": "Nova Col\u00b7lecci\u00f3", + "LabelCollection": "Col\u00b7lecci\u00f3:", + "Help": "Ajuda", + "LabelDisplayMode": "Display mode:", + "Desktop": "Escriptori", + "Mobile": "M\u00f2bil \/ Tauleta", + "TV": "TV", + "DisplayModeHelp": "Selecciona el tipus de pantalla en el que tens Emby funcionant.", + "LabelDisplayLanguage": "Idioma de visualitzaci\u00f3:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Les col\u00b7leccions et permeten crear agrupacions personalitzades de pel\u00b7l\u00edcules i altres continguts.", + "SearchForCollectionInternetMetadata": "Cerca a internet artwork i metadades", + "DisplayMissingEpisodesWithinSeasons": "Mostra tamb\u00e9 els episodis que no tingui a les temporades", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Arrenca en iniciar", + "LabelScreensaver": "Salva pantalla:", + "LabelSoundEffects": "Efectes de so:", + "LabelSkin": "Aspecte:", + "LabelName": "Nom:", + "NewCollectionNameExample": "Exemple: Col\u00b7leci\u00f3 Star Wars", + "MessageItemsAdded": "\u00cdtems afegits.", + "OptionNew": "Nou...", + "LabelPlaylist": "Llista de rep.:", + "AddToPlaylist": "Afegeix a la llista de reproducci\u00f3", + "HeaderAddToPlaylist": "Afegir a la llista de reproducci\u00f3", + "Subtitles": "Subt\u00edtols", + "LabelTheme": "Tema:", + "LabelDashboardTheme": "Tema del tauler de control del servidor:", + "SearchForSubtitles": "Cerca Subt\u00edtols", + "LabelLanguage": "Idioma:", + "Search": "Cerca", + "NoSubtitleSearchResultsFound": "No s'han trobat resultats.", + "File": "Fitxer", + "MessageAreYouSureDeleteSubtitles": "Est\u00e0s segur que vols eliminar aquest fitxer de subt\u00edtols?", + "ConfirmDeletion": "Confirma supressi\u00f3", + "MySubtitles": "Els meus subt\u00edtols", + "MessageDownloadQueued": "Desc\u00e0rrega encuada.", + "EditSubtitles": "Edita subt\u00edtols", + "UnlockGuide": "Guia de desbloqueig", + "RefreshMetadata": "Refresca metadades", + "ReplaceExistingImages": "Reempla\u00e7a imatges existents", + "ReplaceAllMetadata": "Reempla\u00e7a totes les metadades", + "SearchForMissingMetadata": "Cerca metadades perdudes", + "LabelRefreshMode": "Mode de refresc:", + "NoItemsFound": "No s'han trobat \u00edtems.", + "HeaderSaySomethingLike": "Digues alguna cosa com...", + "ButtonTryAgain": "Intenta-ho de nou", + "HeaderYouSaid": "Has dit...", + "MessageWeDidntRecognizeCommand": "Ho sentim, no reconeixem aquesta comanda.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Sense valorar", + "Favorite": "Favorit", + "Like": "M'agrada", + "Dislike": "No m'agrada", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Obre", + "Play": "Reprodueix", + "AddToPlayQueue": "Afegeix a la llista de reproducci\u00f3", + "Shuffle": "Aleatori", + "Identify": "Identifica", + "EditImages": "Edita imatges", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sincronitza", + "InstantMix": "Mescla instant\u00e0nia", + "ViewAlbum": "Veure \u00e0lbum", + "ViewArtist": "Veure artista", + "QueueAllFromHere": "Afegeix tots a la cua des d'aqu\u00ed", + "PlayAllFromHere": "Reprodueix tots des d'aqu\u00ed", + "PlayFromBeginning": "Reprodueix des de l'inici", + "ResumeAt": "Reprodueix des de {0}", + "RemoveFromPlaylist": "Esborra de la llista de reproducci\u00f3", + "RemoveFromCollection": "Elimina de la col\u00b7lecci\u00f3", + "Sort": "Sort", + "Trailer": "Tr\u00e0iler", + "MarkPlayed": "Marca com a reprodu\u00eft", + "MarkUnplayed": "Marca com a no reprodu\u00eft", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Prova el Multi-Select", + "TryMultiSelectMessage": "Per editar m\u00faltiples mitjans multim\u00e8dia simplement fes clic i mantingues premut sobre qualsevol cartell i despr\u00e9s selecciona els \u00edtems que vulguis gestionar. Prova-ho!", + "HeaderConfirmRecordingCancellation": "Confirmar Cancel\u00b7laci\u00f3 de l'Enregistrament", + "MessageConfirmRecordingCancellation": "Est\u00e0s segur que vols cancel\u00b7lar aquest enregistrament?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Tipus de contingut:", + "LabelPath": "Directori:", + "Playlists": "Llistes de reproducci\u00f3", + "LabelTitle": "T\u00edtol:", + "LabelOriginalTitle": "T\u00edtol original:", + "LabelSortTitle": "T\u00edtol d'endre\u00e7at:", + "LabelDateAdded": "Data afegit:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Estat:", + "LabelArtists": "Artistes:", + "LabelArtistsHelp": "Separa'n varis emprant ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "\u00c0lbum:", + "Artists": "Artistes", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Valoraci\u00f3 de la comunitat:", + "LabelCriticRating": "Valoraci\u00f3 cr\u00edtica:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Sinopsi:", + "LabelShortOverview": "Sinopsi curta:", + "LabelReleaseDate": "Data de publicaci\u00f3:", + "LabelYear": "Any:", + "LabelPlaceOfBirth": "Lloc de naixement:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Relaci\u00f3 d'aspecte original:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "Identificadors externs:", + "HeaderDisplaySettings": "Opcions de Visualitzaci\u00f3", + "LabelDisplayOrder": "Ordre de visualitzaci\u00f3:", + "Display": "Display", + "Countries": "Pa\u00efsos", + "Genres": "G\u00e8neres", + "Studios": "Estudis", + "Tags": "Etiquetes", + "HeaderMetadataSettings": "Prefer\u00e8ncies de Metadades", + "People": "Gent", + "LabelMetadataDownloadLanguage": "Idioma preferit de desc\u00e0rrega:", + "LabelLockItemToPreventChanges": "Bloca aquest \u00edtem per evitar canvis futurs", + "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", + "LabelCountry": "Pa\u00eds:", + "LabelDynamicExternalId": "Identificador {0}:", + "LabelBirthYear": "Any de naixement:", + "LabelBirthDate": "Data de naixement:", + "LabelDeathDate": "Data de defunci\u00f3:", + "LabelEndDate": "Data de finalitzaci\u00f3:", + "LabelSeasonNumber": "Temporada:", + "LabelEpisodeNumber": "Episodi:", + "LabelTrackNumber": "Pista:", + "LabelNumber": "Nombre:", + "LabelDiscNumber": "Disc:", + "LabelParentNumber": "Parent number:", + "SortName": "Nom per endre\u00e7ar:", + "ReleaseDate": "Data de publicaci\u00f3", + "Continuing": "Continuant", + "Ended": "Acabades", + "HeaderEnabledFields": "Camps Habilitats", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Imatges", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Valoraci\u00f3 Parental", + "PlayCount": "Play count", + "Name": "Nom", + "Overview": "Overview", + "LabelType": "Tipus:", + "LabelPersonRole": "Rol:", + "LabelPersonRoleHelp": "Exemple: Conductor de cami\u00f3 de gelats", + "Actor": "Actor", + "Composer": "Compositor", + "Director": "Director", + "GuestStar": "Artista convidat", + "Producer": "Productor", + "Writer": "Escriptor", + "MessageNoSyncJobsFound": "No s'han trobat desc\u00e0rregues. Crea noves tasques de desc\u00e0rrega emprant els botons de \"Descarrega\" que trobar\u00e0s per tota l'app.", + "MessageNoDownloadsFound": "No s'han trobat desc\u00e0rregues sense connexi\u00f3. Descarrega mitjans per reproduir sense connexi\u00f3 emprant els botons de \"Descarrega\" que trobar\u00e0s per tota l'app.", + "InstallingPackage": "Instal\u00b7lant {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "Instal\u00b7laci\u00f3 {0} cancel\u00b7lada.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodis", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 v\u00eddeo musical", + "ValueMusicVideoCount": "{0} v\u00eddeos musicals", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "\u00cdtem desat.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Reinicia el Servidor d'Emby si et plau - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Qualitat:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Descarregant...", + "HeaderSyncRequiresSub": "Descarregar requereix una subscripci\u00f3 activa d'Emby Premiere.", + "LearnMore": "Learn more", + "LabelProfile": "Perfil:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Descarrega nom\u00e9s els v\u00eddeos no vists", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Nom\u00e9s els v\u00eddeos no vists seran descarregats, i els v\u00eddeos seran eliminats del dispositiu un cop s'hagin vist.", + "AutomaticallySyncNewContent": "Descarrega nou contingut autom\u00e0ticament", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Selecciona el dispositiu on ho vulguis descarregar.", + "Screenshots": "Captures de pantalla", + "MoveRight": "Moure a la dreta", + "MoveLeft": "Moure a l'esquerra", + "ConfirmDeleteImage": "Esborrar imatge?", + "HeaderEditImages": "Edita Imatges", + "Settings": "Prefer\u00e8ncies", + "ShowIndicatorsFor": "Mostra indicadors per a:", + "NewEpisodes": "Nous episodis", + "Episodes": "Episodis", + "HDPrograms": "Programes HD", + "Programs": "Programes", + "LiveBroadcasts": "Live broadcasts", + "Premieres": "Premieres", + "RepeatEpisodes": "Repetir episodis", + "DvrSubscriptionRequired": "Emby DVR requires an active Emby Premiere subscription.", + "HeaderCancelRecording": "Cancel\u00b7lar Enregistrament", + "CancelRecording": "Cancel\u00b7la enregistrament", + "HeaderKeepRecording": "Continuar Enregistrant", + "HeaderCancelSeries": "Cancel\u00b7lar S\u00e8ries", + "HeaderKeepSeries": "Mantenir S\u00e8ries", + "HeaderLearnMore": "Saber-ne M\u00e9s", + "DeleteMedia": "Esborra", + "SeriesSettings": "Prefer\u00e8ncies de la s\u00e8rie", + "HeaderRecordingOptions": "Opcions d'Enregistrament", + "CancelSeries": "Cancel\u00b7la s\u00e8rie", + "DoNotRecord": "No enregistris", + "HeaderSeriesOptions": "Opcions de S\u00e8ries", + "LabelChannels": "Canals:", + "ChannelNameOnly": "Channel {0} only", + "Anytime": "Anytime", + "AnyLanguage": "Any language", + "AroundTime": "Cap a les {0}", + "All": "All", + "AllChannels": "Tots els canals", + "LabelRecord": "Enregistra:", + "NewEpisodesOnly": "Nom\u00e9s nous episodis", + "AllEpisodes": "Tots els episodis", + "LabelStartWhenPossible": "Inicia quan sigui possible:", + "LabelStopWhenPossible": "Atura quan sigui possible:", + "MinutesBefore": "minuts abans", + "MinutesAfter": "minuts despr\u00e9s", + "SkipEpisodesAlreadyInMyLibrary": "No enregistris episodis que ja estan a la meva biblioteca", + "SkipEpisodesAlreadyInMyLibraryHelp": "Els episodis es compararan emprant la temporada i el nombre d'episodi quan siguin disponibles.", + "LabelKeepUpTo": "Mantingues fins a:", + "AsManyAsPossible": "Tants com sigui possible", + "DefaultErrorMessage": "Hi ha hagut un error processant la petici\u00f3. Intenta-ho m\u00e9s tard si et plau.", + "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": "Reprodu\u00eft recentment", + "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": "Restaura Compra", + "ButtonUnlockWithPurchase": "Unlock with Purchase", + "ButtonUnlockPrice": "Unlock {0}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Eliminant del dispositiu", + "KeepOnDevice": "Mantingues al dispositiu", + "CancelDownload": "Cancel\u00b7la desc\u00e0rrega", + "SyncJobItemStatusReadyToTransfer": "Llest per transferir", + "SyncJobItemStatusSyncedMarkForRemoval": "Eliminant del dispositiu", + "SyncJobItemStatusQueued": "Encuat", + "SyncJobItemStatusConverting": "Convertint", + "SyncJobItemStatusTransferring": "Transferint", + "SyncJobItemStatusSynced": "Descarregat", + "SyncJobItemStatusFailed": "Fallit", + "SyncJobItemStatusRemovedFromDevice": "Eliminat del dispositiu", + "SyncJobItemStatusCancelled": "Cancel\u00b7lat", + "Retry": "Reintenta", + "HeaderMyDevice": "El meu dispositiu", + "Continue": "Continua", + "ContinueInSecondsValue": "Continua en {0} segons", + "HeaderRemoteControl": "Control Remot", + "Disconnect": "Desconnecta", + "EnableDisplayMirroring": "Habilita la vista de mirall", + "HeaderPlayOn": "Play On", + "Quality": "Qualitat", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Relaci\u00f3 d'aspecte", + "Original": "Original", + "Fill": "Omplir", + "BestFit": "Millor ajustament", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accepta", + "Reject": "Rebutja", + "Connect": "Connecta", + "HeaderMyMedia": "Els meus mitjans", + "HeaderMyMediaSmall": "Els meus mitjans (petit)", + "LatestFromLibrary": "Novetats a {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continua Veient", + "HeaderContinueListening": "Continua Escoltant", + "HeaderActiveRecordings": "Enregistraments Actius", + "HeaderLatestRecordings": "Darrers Enregistraments", + "LabelSyncTo": "Sincronitza a:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "A continuaci\u00f3", + "HeaderLatestFrom": "Novetats a {0}", + "LabelHomeScreenSectionValue": "Secci\u00f3 {0} de la p\u00e0gina d'inici:", + "SettingsSaved": "Prefer\u00e8ncies desades.", + "None": "Cap", + "More": "M\u00e9s", + "Up": "Amunt", + "Down": "Avall", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "P\u00e0gina d'Inici", + "HeaderLatestChannelItems": "Darrers \u00edtems del canal", + "HeaderLibraryOrder": "Ordre de la llibreria", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "En Directe Ara", + "HeaderPlaybackError": "Error de Reproducci\u00f3", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Sugger\u00e8ncies", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Llistes de Reproducci\u00f3 Preferides", + "Collections": "Collections", + "LabelSelectFolderGroups": "Agrupa autom\u00e0ticament el contingut de les seg\u00fcents carpetes en col\u00b7leccions com Pel\u00b7l\u00edcules, M\u00fasica i TV:", + "LabelSelectFolderGroupsHelp": "Les carpetes desmarcades ser\u00e1n mostrades individualment en la seva pr\u00f2pia vista.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Directoris de la Llibreria", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Marca com a vist", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Format de subt\u00edtol no suportat", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Mode de subt\u00edtol:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "Sense subt\u00edtols", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Nom\u00e9s subt\u00edtols for\u00e7ats", + "AlwaysPlaySubtitles": "Reprodueix sempre amb subt\u00edtols", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Prefer\u00e8ncies de subt\u00edtols", + "HeaderSubtitleAppearance": "Apari\u00e8ncia de subt\u00edtols", + "OnlyForcedSubtitlesHelp": "Nom\u00e9s es carregaran aquells subt\u00edtols marcats com a for\u00e7ats.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Idioma preferit de subt\u00edtols:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "Aquestes prefer\u00e8ncies afecten els subt\u00edtols d'aquest dispositiu", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Esperant Wifi", + "WifiRequiredToDownload": "Es requereix una connexi\u00f3 Wifi per continuar descarregant.", + "HeaderDownloadSettings": "Prefer\u00e8ncies de desc\u00e0rregues", + "Hide": "Amaga", + "HeaderStartNow": "Comen\u00e7ar Ara", + "HeaderNextVideoPlayingInValue": "Reproduint proper v\u00eddeo en {0}", + "HeaderNextEpisodePlayingInValue": "Reproduint proper episodi en {0}", + "HeaderSecondsValue": "{0} segons", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Habilitar mode cinema", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Darrers MItjans", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/cs.json b/src/bower_components/emby-webcomponents/strings/cs.json index eb9291a360..9b2ce69853 100644 --- a/src/bower_components/emby-webcomponents/strings/cs.json +++ b/src/bower_components/emby-webcomponents/strings/cs.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Přijmout", - "AccessRestrictedTryAgainLater": "Přístup je v současné době omezen. Prosím zkuste to znovu později.", - "Actor": "Herec", - "Add": "Přidat", - "AddToCollection": "Přidat do kolekce", - "AddToPlayQueue": "Přidat do fronty k přehrání", - "AddToPlaylist": "Přidat do playlistu", - "AddedOnValue": "Přidáno {0}", - "Advanced": "Pokročilé", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Alba", - "All": "Vše", - "AllChannels": "Všechny kanály", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Všechny epizody", - "AllLanguages": "Všechny jazyky", - "AllowSeasonalThemes": "Povolit automatická sezónní témata", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Vždy zobrazit titulky", - "AlwaysPlaySubtitlesHelp": "Titulky odpovídající jazykové předvolbě se načtou bez ohledu na jazyk audia.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Kdykoliv", - "AroundTime": "Okolo {0}", - "Art": "Umění", - "Artists": "Umělci", - "AsManyAsPossible": "Tolikrát jak je možné", - "Ascending": "Ascending", - "AspectRatio": "Poměr stran", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "Nové", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Datový tok audia není podporován", - "AudioChannelsNotSupported": "Audio kanály nejsou podporovány", - "AudioCodecNotSupported": "Audio kodek není podporován", - "AudioProfileNotSupported": "Audio profil není podporován", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Automatizovat", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automaticky stahovat nový obsah", - "AutomaticallySyncNewContentHelp": "Nový obsah přidaný do této složky bude automaticky stažen do zařízení.", - "Backdrop": "Pozadí", - "Backdrops": "Pozadí", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Místo narození", - "Books": "Knihy", - "Box": "Pouzdro", - "BoxRear": "Zadní část pouzdra", - "Browse": "Procházet", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Zrušit", - "ButtonGotIt": "Mám to", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Přehrát jednu minutu", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Obnovit nákup", - "ButtonTryAgain": "Zkusit znovu", - "ButtonUnlockPrice": "Odemknout {0}", - "ButtonUnlockWithPurchase": "Odemkněte pomocí koupě", - "CancelDownload": "Zrušit stahování", - "CancelRecording": "Zrušit nahrávání", - "CancelSeries": "Ukončit Seriál", - "Categories": "Kategorie", - "ChannelNameOnly": "Kanál {0} jen", - "ChannelNumber": "Číslo kanálu", - "CinemaModeConfigurationHelp": "Režim Cinema přináší zážitky jako z kina přímo do vašeho obývacího pokoje s možností přehrát trailery a vlastní intra před hlavním programem.", - "CinemaModeFeatureDescription": "S režimem Kino získate funkci, která před hlavním programem přehraje trailery a uživatelská intra.", - "CloudSyncFeatureDescription": "Synchronizujte vaše média na cloud pro jednodušší zálohování, archivaci a konverzi.", - "Collections": "Kolekce", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Hodnocení komunity", - "Composer": "Skladatel", - "ConfigureDateAdded": "Konfigurace přidání data je definována v nastavení knihovny v ovládacím panelu", - "ConfirmDeleteImage": "Odstranit obrázek?", - "ConfirmDeleteItem": "Smazáním položky odstraníte soubor jak z knihovny médií tak ze souborového systému. Jste si jisti, že chcete pokračovat?", - "ConfirmDeleteItems": "Odstraněním těchto položek odstraníte vaše média jak z knihovny médií, tak i ze souborového systému. Jste si jisti, že chcete pokračovat?", - "ConfirmDeletion": "Potvrdit smazání", - "ConfirmEndPlayerSession": "Chcete vypnout Jellyfin na {0}?", - "ConfirmRemoveDownload": "Odebrat stažení?", - "Connect": "Připojit", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Kontejner není podporován", - "Continue": "Pokračovat", - "ContinueInSecondsValue": "Pokračovat za {0} sekund.", - "ContinueWatching": "Pokračovat ve sledování", - "Continuing": "Pokračování", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Země", - "CriticRating": "Critic rating", - "DateAdded": "Datum přidání", - "DatePlayed": "Datum přehrání", - "Days": "Dny", - "Default": "Výchozí", - "DefaultErrorMessage": "Došlo k chybě při zpracování požadavku. Prosím zkuste to znovu později.", - "DefaultSubtitlesHelp": "Titulky jsou načteny na základě výchozích a vynucených nastavení ve vložených metadatech. Jazykové preference jsou vzaty v úvahu, pokud je k dispozici více možností.", - "Delete": "Odstranit", - "DeleteMedia": "Odstranit média", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "PC", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Přímé přehrání", - "DirectStreamHelp1": "Médium je kompatibilní se zařízením, pokud jde o rozlišení a typ média (H.264, AC3, atd.), ale je v nekompatibilním kontejneru (.mkv, .avi, .wmv, atd.). Video bude za běhu přebaleno než bude streamováno do zařízení.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Přímé streamování", - "Director": "Režisér", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disk", - "Disconnect": "Odpojit", - "Dislike": "Nemám rád", - "Display": "Zobrazení", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Zobrazit chybějící epizody", - "DisplayMissingEpisodesWithinSeasonsHelp": "Musí být zapnuto pro knihovny TV v nastavení Jellyfin Server", - "DisplayModeHelp": "Zvolte typ obrazovky, na které používáte Jellyfin.", - "DoNotRecord": "Nenahrávat", - "Down": "Dolů", - "Download": "Stáhnout", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Staženo", - "Downloading": "Stahování", - "DownloadingDots": "Stahování...", - "Downloads": "Stahování", - "DownloadsValue": "{0} downloads", - "DropShadow": "Vrhat stín", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR vyžaduje aktivní předplatné Jellyfin Premiere.", - "Edit": "Upravit", - "EditImages": "Editace obrázků", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Editovat titulky", - "EnableBackdrops": "Povolit pozadí", - "EnableBackdropsHelp": "Pokud je povoleno, pozadí je zobrazeno pro některé stránky při procházení vaší knihovny.", - "EnableCinemaMode": "Povolit Cinema Mód", - "EnableColorCodedBackgrounds": "Aktivovat barevně označené pozadí", - "EnableDisplayMirroring": "Povolit zrcadlení obrazu", - "EnableExternalVideoPlayers": "Povolit externí video přehrávače", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Povolit informaci o následujícím videu během přehrávání", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Povolit tématickou hudbu na pozadí", - "EnableThemeSongsHelp": "Pokud povolíte, bude při procházení knihovny na pozadí přehrávána tématická melodie.", - "EnableThemeVideos": "Povolit tématické video", - "EnableThemeVideosHelp": "Pokud povolíte, bude při procházení knihovny přehráváno tématické video na pozadí.", - "Ended": "Ukončeno", - "EndsAtValue": "Končí v {0}", - "Episodes": "Epizody", - "Error": "Chyba", - "ErrorAddingGuestAccount1": "Došlo k chybě při přidávání účtu Jellyfin Connect. Má váš host vytvořený účet Jellyfin? Může se přihlásit na {0}.", - "ErrorAddingGuestAccount2": "Pokud stále máte problémy, pošlete prosím e-mail na adresu {0} a přiložte Vaši i jejich e-mailovou adresu.", - "ErrorAddingJellyfinConnectAccount1": "Nastala chyba při přidávání účtu Jellyfin Connect. Opravdu máte vytvořen účet u Jellyfin? Přihlaste se zde {0}.", - "ErrorAddingJellyfinConnectAccount2": "Pokud stále máte problémy, pošlete prosím e-mail na adresu {0} z e-mailové adresy použité na účtu Jellyfin.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "Nastala chyba při mazání položky z Jellyfin Serveru. Zkontrolujte prosím, že Jellyfin Server má oprávnění k zápisu do složky médií a zkuste to prosím znovu.", - "ErrorReachingJellyfinConnect": "Došlo k chybě při navázání spojení k serveru Jellyfin Connect. Ujistěte se, zda je funkční připojení k internetu a zkuste to znovu.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra velký", - "Extras": "Extras", - "Favorite": "Oblíbené", - "Favorites": "Oblíbené", - "FeatureRequiresJellyfinPremiere": "Tato funkce vyžaduje aktivní předplatné Jellyfin Premiere.", - "Features": "Features", - "File": "Soubor", - "Fill": "Vyplnit", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Formát: {0}", - "FreeAppsFeatureDescription": "Užijte si výběr Jellyfin aplikací zdarma pro vaše zařízení.", - "Friday": "Pátek", - "GenreValue": "Genre: {0}", - "Genres": "Žánry", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Skupinové verze", - "GuestStar": "Hostující hvězda", - "GuestUserNotFound": "Uživatel nenalezen. Prosím, ujistěte se, že název je správný a zkuste to znovu, nebo zkuste zadat jejich e-mailovou adresu.", - "Guide": "Průvodce", - "HDPrograms": "HD programy", - "HeaderActiveRecordings": "Aktivní nahrávání", - "HeaderAddToCollection": "Přidat do Kolekce", - "HeaderAddToPlaylist": "Přidat do playlistu", - "HeaderAddUpdateImage": "Přidat/Aktualizovat obrázek", - "HeaderAlbumArtists": "Umělci alba", - "HeaderAlreadyPaid": "Již zaplaceno?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio knihy", - "HeaderAudioSettings": "Nastavení zvuku", - "HeaderBecomeProjectSupporter": "Získat Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Výhody Jellyfin Premiere", - "HeaderCancelRecording": "Zrušit nahrávání", - "HeaderCancelSeries": "Ukončit Seriál", - "HeaderCinemaMode": "Cinema Mód", - "HeaderCloudSync": "Synchronizace s Cloudem", - "HeaderConfirmRecordingCancellation": "Potvrzení zrušení nahrávání", - "HeaderContinueListening": "Pokračovat v poslechu", - "HeaderContinueWatching": "Pokračovat ve sledování", - "HeaderConvertYourRecordings": "Konverze vašich nahrávek", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Smazat položku", - "HeaderDeleteItems": "Odstranit položky", - "HeaderDisplaySettings": "Nastavení zobrazení", - "HeaderDownloadSettings": "Stáhnout nastavení", - "HeaderEditImages": "Editace obrázků", - "HeaderEnabledFields": "Povolené pole", - "HeaderEnabledFieldsHelp": "Zrušte zaškrtnutí, abyste zabránily změnám dat.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Jellyfin Apps zdarma", - "HeaderHomeScreen": "Domovská obrazovka", - "HeaderIdentifyItemHelp": "Zadejte jedno nebo více vyhledávacích kritérií. Odstraňte kritéria pro vyhledání více výsledků.", - "HeaderInvitationSent": "Pozvánka odeslána", - "HeaderJellyfinAccountAdded": "Jellyfin účet přidán", - "HeaderJellyfinAccountRemoved": "Jellyfin účet odebrán", - "HeaderKeepRecording": "Udržet nahrávání", - "HeaderKeepSeries": "Udržet seriál", - "HeaderLatestChannelItems": "Nejnovější položky kanálu", - "HeaderLatestChannelMedia": "Nejnovější položky kanálu", - "HeaderLatestFrom": "Nejnovější od {0}", - "HeaderLatestMedia": "Nejnovější média", - "HeaderLatestRecordings": "Nejnovější nahrávky", - "HeaderLearnMore": "Zjistit více", - "HeaderLibraryFolders": "Složky knihovny", - "HeaderLibraryOrder": "Pořadí knihovny", - "HeaderMetadataSettings": "Nastavení metadat", - "HeaderMusicQuality": "Kvalita hudby", - "HeaderMyDevice": "Moje zařízení", - "HeaderMyDownloads": "Moje stahování", - "HeaderMyMedia": "Moje média", - "HeaderMyMediaSmall": "Moje média (malé)", - "HeaderNewRecording": "Nový záznam", - "HeaderNextEpisodePlayingInValue": "Přehrávání další epizody za {0}", - "HeaderNextUp": "Nadcházející", - "HeaderNextVideoPlayingInValue": "Přehrávání dalšího videa za {0}", - "HeaderOfflineDownloads": "Offline média", - "HeaderOfflineDownloadsDescription": "Stáhnout média do vašeho zařízení pro snadné použití offline.", - "HeaderOnNow": "Právě teď", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Přehrát moje Média", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Chyba přehrávání", - "HeaderRecordingOptions": "Nastavení nahrávání", - "HeaderRemoteControl": "Dálkový ovladač", - "HeaderRestartingJellyfinServer": "Restartování Jellyfin serveru", - "HeaderSaySomethingLike": "Vyslovte něco jako...", - "HeaderSecondsValue": "{0} sekund", - "HeaderSelectDate": "Vyber datum", - "HeaderSeriesOptions": "Nastavení seriálu", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Infromace o speciální epizodě", - "HeaderStartNow": "Začít teď", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Vzhled titulků", - "HeaderSubtitleSettings": "Nastavení titulků", - "HeaderSyncRequiresSub": "Stahování vyžaduje aktivní předplatné Jellyfin Premiere.", - "HeaderTermsOfPurchase": "Podmínky nákupu", - "HeaderTryPlayback": "Zkusit playback", - "HeaderUnlockFeature": "Odemknout funkci", - "HeaderUploadImage": "Nahrát obrázek", - "HeaderVideoQuality": "Kvalita videa", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Čekání na Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "Zmínil ses...", - "Help": "Nápověda", - "Hide": "Skrýt", - "HideWatchedContentFromLatestMedia": "Skrýt přehrané položky ze seznamu nejnovějších médií", - "Home": "Domů", - "Horizontal": "Horizontal", - "HowDidYouPay": "Jak chcete platit?", - "IHaveJellyfinPremiere": "Již mám Jellyfin Premiere", - "IPurchasedThisApp": "Tuto aplikaci mám již zaplacenu", - "Identify": "Identifikuj", - "Images": "Obrázky", - "ImdbRating": "Hodnocení IMDb", - "InstallingPackage": "Instalace {0}", - "InstantMix": "Okamžité míchání", - "InterlacedVideoNotSupported": "Prokládané video není podporováno", - "ItemCount": "{0} položek", - "Items": "Položky", - "KeepDownload": "Keep download", - "KeepOnDevice": "Ponechat na zařízení", - "Kids": "Dětské", - "Label3DFormat": "3D formát:", - "LabelAirDays": "Vysíláno:", - "LabelAirTime": "Čas vysílání:", - "LabelAirsAfterSeason": "Vysíláno po sezóně:", - "LabelAirsBeforeEpisode": "Vysíláno před epizodou:", - "LabelAirsBeforeSeason": "Vysíláno před sezónou:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Alba umělce:", - "LabelArtists": "Úmělci", - "LabelArtistsHelp": "Odděl pomocí ;", - "LabelAudio": "Zvuk:", - "LabelAudioLanguagePreference": "Preferovaný jazyk zvuku:", - "LabelBirthDate": "Datum narození:", - "LabelBirthYear": "Rok narození:", - "LabelBitrateMbps": "Datový tok (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Kanály:", - "LabelCollection": "Kolekce:", - "LabelCommunityRating": "Hodnocení komunity:", - "LabelContentType": "Typ obsahu:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Země:", - "LabelCriticRating": "Hodnocení kritiků:", - "LabelCustomRating": "Vlastní hodnocení:", - "LabelDashboardTheme": "Téma hlavní nabídky serveru:", - "LabelDateAdded": "Datum přidání:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Datum úmrtí:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Číslo disku:", - "LabelDisplayLanguage": "Jazyk rozhraní:", - "LabelDisplayLanguageHelp": "Překlad Jellyfin je projekt ve fázi neustálého vývoje.", - "LabelDisplayMode": "Režim zobrazení:", - "LabelDisplayOrder": "Pořadí zobrazení:", - "LabelDropImageHere": "Sem přetáhněte obrázek nebo klikněte pro procházení.", - "LabelDropShadow": "Vrhat stín:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mailová adresa:", - "LabelEndDate": "Datum ukončení:", - "LabelEpisodeNumber": "Číslo epizody:", - "LabelFont": "Písmo:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Domovská obrazovka sekce {0}", - "LabelImageType": "Typ obrázku:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Limit položek:", - "LabelKeep:": "Udržet:", - "LabelKeepUpTo": "Aktualizovat k:", - "LabelLanguage": "Jazyk:", - "LabelLockItemToPreventChanges": "Uzamknout položku pro zabránění budoucích změn", - "LabelMaxChromecastBitrate": "Maximální datový tok pro Chromecast:", - "LabelMetadataDownloadLanguage": "Preferovaný jazyk:", - "LabelName": "Jméno:", - "LabelNumber": "Číslo:", - "LabelOriginalAspectRatio": "Původní poměr stran:", - "LabelOriginalTitle": "Originální název:", - "LabelOverview": "Přehled:", - "LabelParentNumber": "Číslo rodičovského prvku", - "LabelParentalRating": "Rodičovské hodnocení:", - "LabelPath": "Cesta k souboru:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Příklad: Řidič kamiónu se zmrzlinou", - "LabelPlaceOfBirth": "Místo narození:", - "LabelPlayDefaultAudioTrack": "Přehrávat defaultní audio stopu bez ohledu na jazyk", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferovaný jazyk titulků:", - "LabelProfile": "Profil:", - "LabelQuality": "Kvalita:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Záznam:", - "LabelRefreshMode": "Mód obnovy:", - "LabelReleaseDate": "Datum vydání:", - "LabelRuntimeMinutes": "Délka (v minutách):", - "LabelScreensaver": "Šetřič obrazovky:", - "LabelSeasonNumber": "Číslo sezóny:", - "LabelSelectFolderGroups": "Automaticky seskupit obsah z následujících složek do zobrazení, jako jsou Filmy, Hudba a TV:", - "LabelSelectFolderGroupsHelp": "Složky, které nejsou zaškrtnuty budou zobrazeny ve vlastním pohledu.", - "LabelShortOverview": "Hlavní linie:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Délka posunu zpět:", - "LabelSkipForwardLength": "Délka posunu vpřed:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Třídit dle názvu:", - "LabelSoundEffects": "Zvukové efekty:", - "LabelSource": "Zdroj:", - "LabelStartWhenPossible": "Začít jakmile je to možné:", - "LabelStatus": "Stav:", - "LabelStopWhenPossible": "Zastavit jakmile je to možné:", - "LabelSubtitlePlaybackMode": "Mód titulků:", - "LabelSubtitles": "Titulky:", - "LabelSyncJobName": "Název Sync úlohy:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync do:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Slogan:", - "LabelTextBackgroundColor": "Barva pozadí textu:", - "LabelTextColor": "Barva textu:", - "LabelTextSize": "Velikost textu:", - "LabelTheme": "Téma:", - "LabelTitle": "Název:", - "LabelTrackNumber": "Číslo stopy:", - "LabelType": "Typ:", - "LabelVersion": "Verze:", - "LabelVideo": "Video:", - "LabelWebsite": "Webové stránky:", - "LabelWindowBackgroundColor": "Barva pozadí textu:", - "LabelYear": "Rok:", - "Large": "Velký", - "LatestFromLibrary": "Nejnovější {0}", - "LearnHowYouCanContribute": "Zjistěte, jak můžete přispět.", - "LearnMore": "Zjistit více", - "Like": "Mám rád", - "LinksValue": "Links: {0}", - "List": "Seznam", - "Live": "Živě", - "LiveBroadcasts": "Přímé přenosy", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV vyžaduje aktivní předplatné Jellyfin Premiere.", - "Logo": "Logo", - "ManageRecording": "Spravovat nahrávání", - "MarkPlayed": "Označit přehrané", - "MarkUnplayed": "Označit nepřehrané", - "MarkWatched": "Označit jako shlédnuté", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Střední", - "Menu": "Nabídka", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Aktivní předplatné Jellyfin Premiere je zapotřebí pro vytvoření automatického nahrávání řad.", - "MessageAreYouSureDeleteSubtitles": "Jste si jisti, že chcete smazat tyto titulky?", - "MessageConfirmRecordingCancellation": "Zrušit nahrávání", - "MessageDownloadQueued": "Stažení zařazeno.", - "MessageFileReadError": "Došlo k chybě při čtení souboru. Prosím zkuste to znovu.", - "MessageIfYouBlockedVoice": "Pokud byl Váš přístup odepřen pomocí hlasové aplikace, budete ji muset překonfigurovat před dalším pokusem.", - "MessageInvitationSentToNewUser": "E-mail byl odeslán na adresu {0} s výzvou k registraci s Jellyfin.", - "MessageInvitationSentToUser": "E-mail byl odeslán na adresu {0} a přijmutím této pozvnánky akceptujete vaší pozvánku ke sdílení.", - "MessageItemSaved": "Položka uložena.", - "MessageItemsAdded": "Položky přidány.", - "MessageJellyfinAccontRemoved": "Účet Jellyfin byl odstraněn pro tohoto uživatele.", - "MessageJellyfinAccountAdded": "Jellyfin účet byl přidáno k tomuto uživateli.", - "MessageLeaveEmptyToInherit": "Při ponechání prázdné položky bude zděděno nastavení z položky nadřazené nebo z globální defaultní hodnoty.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "Žádné servery nejsou k dispozici. Pokud jste byli pozváni na sdílený server, ujistěte se, že jste pozvánku níže akceptovali nebo klikly na odkaz v e-mailu.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "Účet Jellyfin byl přidán pro tohoto uživatele. E-mail bude zaslán majiteli účtu. Pozvánku bude nutné potvrdit kliknutím na odkaz uvnitř e-mailu.", - "MessagePlayAccessRestricted": "Přehrávání tohoto obsahu je momentálně omezeno. Pro více informací kontaktujte prosím Vašeho správce Jellyfin Serveru.", - "MessageToValidateSupporter": "Pokud máte aktivní předplatné Jellyfin Premiere, ujistěte se, že máte nastaven Jellyfin Premiere v panelu Nastavení pod Nápověda -> Jellyfin Premiere.", - "MessageUnlockAppWithPurchaseOrSupporter": "Odemknout tuto funkci pomocí jednorázové platby, nebo pomocí aktivace předplatného Jellyfin Premiere.", - "MessageUnlockAppWithSupporter": "Odemknout tuto funkci pomocí aktivního předplatného Jellyfin Premiere.", - "MessageWeDidntRecognizeCommand": "Je nám líto, příkaz nebyl rozpoznán.", - "MinutesAfter": "minut po", - "MinutesBefore": "minut předem", - "Mobile": "Mobil / Tablet", - "Monday": "Pondělí", - "More": "Více", - "MoveLeft": "Posunout vlevo", - "MoveRight": "Posunout vpravo", - "Movies": "Filmy", - "MySubtitles": "Mé titulky", - "Name": "Název", - "NewCollection": "Nová kolekce", - "NewCollectionHelp": "Kolekce dovolí vytvořit personalizované seskupení filmů a dalšího obsahu knihoven.", - "NewCollectionNameExample": "Příklad: Kolekce Star Wars", - "NewEpisodes": "Nové episody", - "NewEpisodesOnly": "Jen nové epizody", - "News": "Zpravodajství", - "Next": "Další", - "No": "Ne", - "NoItemsFound": "Nenalezeny žádné položky.", - "NoSubtitleSearchResultsFound": "Žádné výsledky.", - "NoSubtitles": "Žádné titulky", - "NoSubtitlesHelp": "Ve výchozím nastavení nebudou titulky načteny. Během přehrávání však mohou být manuálně zapnuty.", - "None": "Žádný", - "Normal": "Normální", - "Off": "Vypnuto", - "OneChannel": "Jeden kanál", - "OnlyForcedSubtitles": "Pouze vynucené titulky", - "OnlyForcedSubtitlesHelp": "Jen vynucené titulky budou nahrány.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Otevřít", - "OptionNew": "Nový...", - "Original": "Originál", - "OriginalAirDateValue": "Datum vysílání originálu: {0}", - "Overview": "Přehled/Obsah", - "PackageInstallCancelled": "Instalace {0} zrušena.", - "PackageInstallCompleted": "Instalace {0} dokončena.", - "PackageInstallFailed": "Instalace {0} selhala!!!", - "ParentalRating": "Rodičovské hodnocení", - "People": "Lidé", - "PerfectMatch": "Přesná shoda", - "Photos": "Fotky", - "PlaceFavoriteChannelsAtBeginning": "Umístit oblíbené kanály na začátek", - "Play": "Přehrát", - "PlayAllFromHere": "Přehrát vše odsud", - "PlayCount": "Počet přehrání", - "PlayFromBeginning": "Přehrát od začátku", - "PlayNext": "Přehrát další", - "PlayNextEpisodeAutomatically": "Automaticky přehrávat další epizodu", - "PlaybackErrorNoCompatibleStream": "Žádné kompatibilní streamy nejsou v současné době k dispozici. Zkuste to prosím později nebo pro více podrobností kontaktujte svého správce systému", - "PlaybackErrorNotAllowed": "V současné době nejste oprávněni přehrávat tento obsah. Pro více informací se obraťte se na správce systému.", - "PlaybackErrorPlaceHolder": "Pro přehrání videa nejdříve vložte disk", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Přehráno", - "Playlists": "Playlisty", - "PleaseEnterNameOrId": "Prosím, zadejte název nebo externí Id.", - "PleaseRestartServerName": "Prosím, restartujte Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Vyberte nejméně dvě položky prosím.", - "Premiere": "Premiéra", - "Premieres": "Premiéry", - "Previous": "Předchozí", - "Primary": "Primární", - "PrivacyPolicy": "Zásady ochrany osobních údajů", - "Producer": "Producent", - "ProductionLocations": "Místo výroby", - "Programs": "Programy", - "PromoConvertRecordingsToStreamingFormat": "Automaticky konvertovat nahrávky do doporučeného streamovacího formátu s Jellyfin Premiere. Nahrávky budou při přehrávání konvertovány do MP4 nebo MKV - dle nastavení Jellyfin server.", - "Quality": "Kvalita", - "QueueAllFromHere": "Zařadit vše do fronty", - "Raised": "Raised", - "RecentlyWatched": "Nedávno shlédnuté", - "Record": "Nahrávat", - "RecordSeries": "Nahrát série", - "RecordingCancelled": "Nahrávání zrušeno.", - "RecordingScheduled": "Plán nahrávání.", - "Recordings": "Nahrávky", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Obnovit", - "RefreshDialogHelp": "Metadata se aktualizují na základě nastavení a internetových služeb, které jsou povoleny v nastavení Jellyfin Server.", - "RefreshMetadata": "Obnovit metadata", - "RefreshQueued": "Obnovení zařazeno.", - "Reject": "Odmítnout", - "ReleaseDate": "Datum vydání", - "RemoveDownload": "Odebrat stažení", - "RemoveFromCollection": "Odebrat z kolekce", - "RemoveFromPlaylist": "Odebrat z playlistu", - "RemovingFromDevice": "Odebírání ze zařízení", - "Repeat": "Opakovat", - "RepeatAll": "Opakovat vše", - "RepeatEpisodes": "Opakovaní epizod", - "RepeatMode": "Mód opakování", - "RepeatOne": "Opakovat jeden", - "ReplaceAllMetadata": "Přepsat všechna metadata", - "ReplaceExistingImages": "Nahradit existující obrázky", - "RestartPleaseWaitMessage": "Počkejte prosím, než se Jellyfin Server vypne a restartuje. Může to trvat pár minut.", - "ResumeAt": "Obnovit přehrávání od {0}", - "Retry": "Opakovat", - "RunAtStartup": "Spustit po startu", - "Runtime": "Délka", - "Saturday": "Sobota", - "Save": "Uložit", - "ScanForNewAndUpdatedFiles": "Vyhledat nové a aktualizované soubory", - "Schedule": "Naplánování úlohy", - "Screenshot": "Snímek obrazovky", - "Screenshots": "Snímky obrazovky", - "Search": "Vyhledávání", - "SearchForCollectionInternetMetadata": "Vyhledat metadata a obrázky na Internetu.", - "SearchForMissingMetadata": "Hledání chybějících metadat", - "SearchForSubtitles": "Vyhledat titulky", - "SearchResults": "Výsledky vyhledávání", - "SecondaryAudioNotSupported": "Přepínání audio stopy není podporováno", - "SeriesCancelled": "Série zrušena.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Plán nahrávání seriálu.", - "SeriesSettings": "Nastavení seriálu", - "SeriesYearToPresent": "{0} - Současnost", - "ServerNameIsRestarting": "Jellyfin Server - {0} je restartován.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} je vypínán.", - "ServerUpdateNeeded": "Tento Jellyfin Server je třeba aktualizovat. Chcete-li stáhnout nejnovější verzi, navštivte prosím {0}", - "Settings": "Nastavení", - "SettingsSaved": "Nastavení uloženo.", - "Share": "Sdílet", - "ShowIndicatorsFor": "Zobrazit indikátor pro:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Seriály", - "Shuffle": "Náhodně", - "SkipEpisodesAlreadyInMyLibrary": "Přeskočit nahrávání epizod, které jsou v knihovně", - "SkipEpisodesAlreadyInMyLibraryHelp": "Epizody budou porovnávány s použitím období a čísla epizody, pokud jsou k dispozici.", - "Small": "Malý", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Chytrý", - "SmartSubtitlesHelp": "Titulky budou načteny po porovnání s preferovaným jazykem, pokud je zvuk v cizím jazyce.", - "Songs": "Skladby", - "Sort": "Sort", - "SortByValue": "Třídit dle {0}", - "SortChannelsBy": "Třídit kanály dle:", - "SortName": "Setřídit dle názvu", - "Sports": "Sport", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Zastavit nahrávání", - "Studios": "Studia", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Formát titulků není podporován", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Titulky", - "Suggestions": "Návrhy", - "Sunday": "Neděle", - "Sync": "Synchronizace", - "SyncJobItemStatusCancelled": "Zrušeno", - "SyncJobItemStatusConverting": "Konverze", - "SyncJobItemStatusFailed": "Selhalo", - "SyncJobItemStatusQueued": "Přidáno do fronty", - "SyncJobItemStatusReadyToTransfer": "Připraveno k přenosu", - "SyncJobItemStatusRemovedFromDevice": "Odebráno ze zařízení", - "SyncJobItemStatusSynced": "Staženo", - "SyncJobItemStatusSyncedMarkForRemoval": "Odebírání ze zařízení", - "SyncJobItemStatusTransferring": "Přenášení", - "SyncUnwatchedVideosOnly": "Stáhnout pouze neshlédnutá videa", - "SyncUnwatchedVideosOnlyHelp": "Pouze neshlédnutá videa budou stažena a budou odstraněna ze zařízení, jakmile je zhlédnete.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tagy", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Podmínky použití", - "ThankYouForTryingEnjoyOneMinute": "Prosím užijte si jednu minutu přehrávání. Děkujeme vám za vyzkoušení Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "Tato nastavení ovlivní titulky na tomto zařízení", - "Thumb": "Miniatura", - "Thursday": "Čtvrtek", - "TrackCount": "{0} stop", - "Trailer": "Ukázka/trailer", - "Trailers": "Trailers", - "Transcoding": "Překódování", - "TryMultiSelect": "Vyzkoušej multi-výběr", - "TryMultiSelectMessage": "Chcete-li upravit více mediálních položek, stačí kliknout a podržet na kterémkoliv plakátu. Poté můžete vybrat více položek, které chcete spravovat. Zkus to!", - "Tuesday": "Úterý", - "Uniform": "Uniform", - "UnlockGuide": "Průvodce pro odemčení", - "Unplayed": "Unplayed", - "Unrated": "Nehodnoceno", - "UntilIDelete": "Dokud nesmažu", - "UntilSpaceNeeded": "Do potřebného prostoru", - "Up": "Nahoru", - "Upload": "Nahrát", - "ValueAlbumCount": "{0} alb", - "ValueDiscNumber": "Disk {0}", - "ValueEpisodeCount": "{0} epizod", - "ValueGameCount": "{0} her", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} filmů", - "ValueMusicVideoCount": "{0} hudebních klipů", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 epizoda", - "ValueOneGame": "1 hra", - "ValueOneItem": "1 položka", - "ValueOneMovie": "1 film", - "ValueOneMusicVideo": "1 hudební klip", - "ValueOneSeries": "1 seriál", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} sekund", - "ValueSeriesCount": "{0} seriálů", - "ValueSongCount": "{0} songů", - "ValueSpecialEpisodeName": "Speciál - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video kodek není podporován", - "VideoFramerateNotSupported": "Snímková frekvence videa není podporována", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profil není podporován", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Rozlišení videa není podporováno", - "ViewAlbum": "Zobrazit album", - "ViewArtist": "Zobrazit úmělce", - "VoiceInput": "Hlasový vstup", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Shlédnuto", - "Wednesday": "Středa", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Napsal", - "Yes": "Ano" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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}", + "LiveTvRequiresUnlock": "Live TV vy\u017eaduje aktivn\u00ed p\u0159edplatn\u00e9 Emby Premiere.", + "AttributeNew": "Nov\u00e9", + "Premiere": "Premi\u00e9ra", + "Live": "\u017div\u011b", + "Repeat": "Opakovat", + "TrackCount": "{0} stop", + "ItemCount": "{0} polo\u017eek", + "OriginalAirDateValue": "Datum vys\u00edl\u00e1n\u00ed origin\u00e1lu: {0}", + "EndsAtValue": "Kon\u010d\u00ed v {0}", + "HeaderSelectDate": "Vyber datum", + "Watched": "Shl\u00e9dnuto", + "AirDate": "Air date", + "Played": "P\u0159ehr\u00e1no", + "ButtonOk": "Ok", + "ButtonCancel": "Zru\u0161it", + "AccessRestrictedTryAgainLater": "P\u0159\u00edstup je v sou\u010dasn\u00e9 dob\u011b omezen. Pros\u00edm zkuste to znovu pozd\u011bji.", + "ButtonGotIt": "M\u00e1m to", + "ButtonRestart": "Restart", + "RecordingCancelled": "Nahr\u00e1v\u00e1n\u00ed zru\u0161eno.", + "SeriesCancelled": "S\u00e9rie zru\u0161ena.", + "RecordingScheduled": "Pl\u00e1n nahr\u00e1v\u00e1n\u00ed.", + "SeriesRecordingScheduled": "Pl\u00e1n nahr\u00e1v\u00e1n\u00ed seri\u00e1lu.", + "HeaderNewRecording": "Nov\u00fd z\u00e1znam", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Ned\u011ble", + "Monday": "Pond\u011bl\u00ed", + "Tuesday": "\u00dater\u00fd", + "Wednesday": "St\u0159eda", + "Thursday": "\u010ctvrtek", + "Friday": "P\u00e1tek", + "Saturday": "Sobota", + "Days": "Dny", + "SortByValue": "T\u0159\u00eddit dle {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Fotky", + "HeaderAppearsOn": "Appears On", + "List": "Seznam", + "RecordSeries": "Nahr\u00e1t s\u00e9rie", + "HeaderCinemaMode": "Cinema M\u00f3d", + "HeaderCloudSync": "Synchronizace s Cloudem", + "Downloads": "Stahov\u00e1n\u00ed", + "HeaderMyDownloads": "Moje stahov\u00e1n\u00ed", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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-mailov\u00e1 adresa:", + "PromoConvertRecordingsToStreamingFormat": "Automaticky konvertovat nahr\u00e1vky do doporu\u010den\u00e9ho streamovac\u00edho form\u00e1tu s Emby Premiere. Nahr\u00e1vky budou p\u0159i 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": "Konverze va\u0161ich nahr\u00e1vek", + "Record": "Nahr\u00e1vat", + "Save": "Ulo\u017eit", + "Edit": "Upravit", + "Download": "St\u00e1hnout", + "Downloaded": "Sta\u017eeno", + "Downloading": "Stahov\u00e1n\u00ed", + "Advanced": "Pokro\u010dil\u00e9", + "Delete": "Odstranit", + "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": "Obnoven\u00ed za\u0159azeno.", + "AddToCollection": "P\u0159idat do kolekce", + "HeaderAddToCollection": "P\u0159idat do Kolekce", + "NewCollection": "Nov\u00e1 kolekce", + "LabelCollection": "Kolekce:", + "Help": "N\u00e1pov\u011bda", + "LabelDisplayMode": "Re\u017eim zobrazen\u00ed:", + "Desktop": "PC", + "Mobile": "Mobil \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Zvolte typ obrazovky, na kter\u00e9 pou\u017e\u00edv\u00e1te Emby.", + "LabelDisplayLanguage": "Jazyk rozhran\u00ed:", + "LabelDisplayLanguageHelp": "P\u0159eklad Emby je projekt ve f\u00e1zi neust\u00e1l\u00e9ho v\u00fdvoje.", + "LearnHowYouCanContribute": "Zjist\u011bte, jak m\u016f\u017eete p\u0159isp\u011bt.", + "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.", + "DisplayMissingEpisodesWithinSeasons": "Zobrazit chyb\u011bj\u00edc\u00ed epizody", + "DisplayMissingEpisodesWithinSeasonsHelp": "Mus\u00ed b\u00fdt zapnuto pro knihovny TV v nastaven\u00ed Emby Server", + "EnableThemeSongs": "Povolit t\u00e9matickou hudbu na pozad\u00ed", + "EnableBackdrops": "Povolit pozad\u00ed", + "EnableThemeSongsHelp": "Pokud povol\u00edte, bude p\u0159i proch\u00e1zen\u00ed knihovny na pozad\u00ed p\u0159ehr\u00e1v\u00e1na t\u00e9matick\u00e1 melodie.", + "EnableBackdropsHelp": "Pokud je povoleno, pozad\u00ed je zobrazeno pro n\u011bkter\u00e9 str\u00e1nky p\u0159i proch\u00e1zen\u00ed va\u0161\u00ed knihovny.", + "EnableThemeVideos": "Povolit t\u00e9matick\u00e9 video", + "EnableThemeVideosHelp": "Pokud povol\u00edte, bude p\u0159i proch\u00e1zen\u00ed knihovny p\u0159ehr\u00e1v\u00e1no t\u00e9matick\u00e9 video na pozad\u00ed.", + "RunAtStartup": "Spustit po startu", + "LabelScreensaver": "\u0160et\u0159i\u010d obrazovky:", + "LabelSoundEffects": "Zvukov\u00e9 efekty:", + "LabelSkin": "Skin:", + "LabelName": "Jm\u00e9no:", + "NewCollectionNameExample": "P\u0159\u00edklad: Kolekce Star Wars", + "MessageItemsAdded": "Polo\u017eky p\u0159id\u00e1ny.", + "OptionNew": "Nov\u00fd...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "P\u0159idat do playlistu", + "HeaderAddToPlaylist": "P\u0159idat do playlistu", + "Subtitles": "Titulky", + "LabelTheme": "T\u00e9ma:", + "LabelDashboardTheme": "T\u00e9ma hlavn\u00ed nab\u00eddky serveru:", + "SearchForSubtitles": "Vyhledat titulky", + "LabelLanguage": "Jazyk:", + "Search": "Vyhled\u00e1v\u00e1n\u00ed", + "NoSubtitleSearchResultsFound": "\u017d\u00e1dn\u00e9 v\u00fdsledky.", + "File": "Soubor", + "MessageAreYouSureDeleteSubtitles": "Jste si jisti, \u017ee chcete smazat tyto titulky?", + "ConfirmDeletion": "Potvrdit smaz\u00e1n\u00ed", + "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": "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", + "HeaderYouSaid": "Zm\u00ednil ses...", + "MessageWeDidntRecognizeCommand": "Je n\u00e1m l\u00edto, p\u0159\u00edkaz nebyl rozpozn\u00e1n.", + "MessageIfYouBlockedVoice": "Pokud byl V\u00e1\u0161 p\u0159\u00edstup odep\u0159en pomoc\u00ed hlasov\u00e9 aplikace, budete ji muset p\u0159ekonfigurovat p\u0159ed dal\u0161\u00edm pokusem.", + "ValueDiscNumber": "Disk {0}", + "Unrated": "Nehodnoceno", + "Favorite": "Obl\u00edben\u00e9", + "Like": "M\u00e1m r\u00e1d", + "Dislike": "Nem\u00e1m r\u00e1d", + "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", + "AddToPlayQueue": "P\u0159idat do fronty k p\u0159ehr\u00e1n\u00ed", + "Shuffle": "N\u00e1hodn\u011b", + "Identify": "Identifikuj", + "EditImages": "Editace obr\u00e1zk\u016f", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "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": "P\u0159ehr\u00e1t od za\u010d\u00e1tku", + "ResumeAt": "Obnovit p\u0159ehr\u00e1v\u00e1n\u00ed od {0}", + "RemoveFromPlaylist": "Odebrat z playlistu", + "RemoveFromCollection": "Odebrat z kolekce", + "Sort": "Sort", + "Trailer": "Uk\u00e1zka\/trailer", + "MarkPlayed": "Ozna\u010dit p\u0159ehran\u00e9", + "MarkUnplayed": "Ozna\u010dit nep\u0159ehran\u00e9", + "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": "Zru\u0161it nahr\u00e1v\u00e1n\u00ed", + "Error": "Chyba", + "VoiceInput": "Hlasov\u00fd vstup", + "LabelContentType": "Typ obsahu:", + "LabelPath": "Cesta k souboru:", + "Playlists": "Playlisty", + "LabelTitle": "N\u00e1zev:", + "LabelOriginalTitle": "Origin\u00e1ln\u00ed n\u00e1zev:", + "LabelSortTitle": "T\u0159\u00eddit dle n\u00e1zvu:", + "LabelDateAdded": "Datum p\u0159id\u00e1n\u00ed:", + "DateAdded": "Datum p\u0159id\u00e1n\u00ed", + "DatePlayed": "Datum p\u0159ehr\u00e1n\u00ed", + "ConfigureDateAdded": "Konfigurace p\u0159id\u00e1n\u00ed data je definov\u00e1na v nastaven\u00ed knihovny v ovl\u00e1dac\u00edm panelu", + "LabelStatus": "Stav:", + "LabelArtists": "\u00dam\u011blci", + "LabelArtistsHelp": "Odd\u011bl pomoc\u00ed ;", + "HeaderAlbumArtists": "Um\u011blci alba", + "LabelAlbumArtists": "Alba um\u011blce:", + "LabelAlbum": "Album:", + "Artists": "Um\u011blci", + "ImdbRating": "Hodnocen\u00ed IMDb", + "CommunityRating": "Hodnocen\u00ed komunity", + "LabelCommunityRating": "Hodnocen\u00ed komunity:", + "LabelCriticRating": "Hodnocen\u00ed kritik\u016f:", + "CriticRating": "Critic rating", + "LabelWebsite": "Webov\u00e9 str\u00e1nky:", + "LabelTagline": "Slogan:", + "LabelOverview": "P\u0159ehled:", + "LabelShortOverview": "Hlavn\u00ed linie:", + "LabelReleaseDate": "Datum vyd\u00e1n\u00ed:", + "LabelYear": "Rok:", + "LabelPlaceOfBirth": "M\u00edsto narozen\u00ed:", + "Aired": "Aired", + "LabelAirDays": "Vys\u00edl\u00e1no:", + "LabelAirTime": "\u010cas vys\u00edl\u00e1n\u00ed:", + "LabelRuntimeMinutes": "D\u00e9lka (v minut\u00e1ch):", + "LabelParentalRating": "Rodi\u010dovsk\u00e9 hodnocen\u00ed:", + "LabelCustomRating": "Vlastn\u00ed hodnocen\u00ed:", + "LabelOriginalAspectRatio": "P\u016fvodn\u00ed pom\u011br stran:", + "Label3DFormat": "3D form\u00e1t:", + "FormatValue": "Form\u00e1t: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "P\u0159esn\u00e1 shoda", + "EnableExternalVideoPlayers": "Povolit extern\u00ed video p\u0159ehr\u00e1va\u010de", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Infromace o speci\u00e1ln\u00ed epizod\u011b", + "LabelAirsBeforeSeason": "Vys\u00edl\u00e1no p\u0159ed sez\u00f3nou:", + "LabelAirsAfterSeason": "Vys\u00edl\u00e1no po sez\u00f3n\u011b:", + "LabelAirsBeforeEpisode": "Vys\u00edl\u00e1no p\u0159ed epizodou:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Nastaven\u00ed zobrazen\u00ed", + "LabelDisplayOrder": "Po\u0159ad\u00ed zobrazen\u00ed:", + "Display": "Zobrazen\u00ed", + "Countries": "Zem\u011b", + "Genres": "\u017d\u00e1nry", + "Studios": "Studia", + "Tags": "Tagy", + "HeaderMetadataSettings": "Nastaven\u00ed metadat", + "People": "Lid\u00e9", + "LabelMetadataDownloadLanguage": "Preferovan\u00fd jazyk:", + "LabelLockItemToPreventChanges": "Uzamknout polo\u017eku pro zabr\u00e1n\u011bn\u00ed budouc\u00edch zm\u011bn", + "MessageLeaveEmptyToInherit": "P\u0159i ponech\u00e1n\u00ed pr\u00e1zdn\u00e9 polo\u017eky bude zd\u011bd\u011bno nastaven\u00ed z polo\u017eky nad\u0159azen\u00e9 nebo z glob\u00e1ln\u00ed defaultn\u00ed hodnoty.", + "LabelCountry": "Zem\u011b:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Rok narozen\u00ed:", + "LabelBirthDate": "Datum narozen\u00ed:", + "LabelDeathDate": "Datum \u00famrt\u00ed:", + "LabelEndDate": "Datum ukon\u010den\u00ed:", + "LabelSeasonNumber": "\u010c\u00edslo sez\u00f3ny:", + "LabelEpisodeNumber": "\u010c\u00edslo epizody:", + "LabelTrackNumber": "\u010c\u00edslo stopy:", + "LabelNumber": "\u010c\u00edslo:", + "LabelDiscNumber": "\u010c\u00edslo disku:", + "LabelParentNumber": "\u010c\u00edslo rodi\u010dovsk\u00e9ho prvku", + "SortName": "Set\u0159\u00eddit dle n\u00e1zvu", + "ReleaseDate": "Datum vyd\u00e1n\u00ed", + "Continuing": "Pokra\u010dov\u00e1n\u00ed", + "Ended": "Ukon\u010deno", + "HeaderEnabledFields": "Povolen\u00e9 pole", + "HeaderEnabledFieldsHelp": "Zru\u0161te za\u0161krtnut\u00ed, abyste zabr\u00e1nily zm\u011bn\u00e1m dat.", + "Backdrops": "Pozad\u00ed", + "Images": "Obr\u00e1zky", + "Runtime": "D\u00e9lka", + "ProductionLocations": "M\u00edsto v\u00fdroby", + "BirthLocation": "M\u00edsto narozen\u00ed", + "ParentalRating": "Rodi\u010dovsk\u00e9 hodnocen\u00ed", + "PlayCount": "Po\u010det p\u0159ehr\u00e1n\u00ed", + "Name": "N\u00e1zev", + "Overview": "P\u0159ehled\/Obsah", + "LabelType": "Typ:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "P\u0159\u00edklad: \u0158idi\u010d kami\u00f3nu se zmrzlinou", + "Actor": "Herec", + "Composer": "Skladatel", + "Director": "Re\u017eis\u00e9r", + "GuestStar": "Hostuj\u00edc\u00ed hv\u011bzda", + "Producer": "Producent", + "Writer": "Napsal", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Instalace {0}", + "PackageInstallCompleted": "Instalace {0} dokon\u010dena.", + "PackageInstallFailed": "Instalace {0} selhala!!!", + "PackageInstallCancelled": "Instalace {0} zru\u0161ena.", + "SeriesYearToPresent": "{0} - Sou\u010dasnost", + "ValueOneItem": "1 polo\u017eka", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} song\u016f", + "ValueOneMovie": "1 film", + "ValueMovieCount": "{0} film\u016f", + "ValueOneSeries": "1 seri\u00e1l", + "ValueSeriesCount": "{0} seri\u00e1l\u016f", + "ValueOneEpisode": "1 epizoda", + "ValueEpisodeCount": "{0} epizod", + "ValueOneGame": "1 hra", + "ValueGameCount": "{0} her", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} alb", + "ValueOneMusicVideo": "1 hudebn\u00ed klip", + "ValueMusicVideoCount": "{0} hudebn\u00edch klip\u016f", + "ValueMinutes": "{0} min", + "Albums": "Alba", + "Songs": "Skladby", + "Books": "Knihy", + "HeaderAudioBooks": "Audio knihy", + "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": "V\u00fdsledky vyhled\u00e1v\u00e1n\u00ed", + "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": "Pros\u00edm, restartujte Emby Server - {0}.", + "LabelSyncJobName": "N\u00e1zev Sync \u00falohy:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Kvalita:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Stahov\u00e1n\u00ed...", + "HeaderSyncRequiresSub": "Stahov\u00e1n\u00ed vy\u017eaduje aktivn\u00ed p\u0159edplatn\u00e9 Emby Premiere.", + "LearnMore": "Zjistit v\u00edce", + "LabelProfile": "Profil:", + "LabelBitrateMbps": "Datov\u00fd tok (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "St\u00e1hnout pouze neshl\u00e9dnut\u00e1 videa", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Pouze neshl\u00e9dnut\u00e1 videa budou sta\u017eena a budou odstran\u011bna ze za\u0159\u00edzen\u00ed, jakmile je zhl\u00e9dnete.", + "AutomaticallySyncNewContent": "Automaticky stahovat nov\u00fd obsah", + "AutomaticallySyncNewContentHelp": "Nov\u00fd obsah p\u0159idan\u00fd do t\u00e9to slo\u017eky bude automaticky sta\u017een do za\u0159\u00edzen\u00ed.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Limit polo\u017eek:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Sn\u00edmky obrazovky", + "MoveRight": "Posunout vpravo", + "MoveLeft": "Posunout vlevo", + "ConfirmDeleteImage": "Odstranit obr\u00e1zek?", + "HeaderEditImages": "Editace obr\u00e1zk\u016f", + "Settings": "Nastaven\u00ed", + "ShowIndicatorsFor": "Zobrazit indik\u00e1tor pro:", + "NewEpisodes": "Nov\u00e9 episody", + "Episodes": "Epizody", + "HDPrograms": "HD programy", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Okolo {0}", + "All": "V\u0161e", + "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 nahr\u00e1v\u00e1n\u00ed epizod, kter\u00e9 jsou v 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:": "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 m\u011bs\u00ed\u010dn\u011b {0}", + "HeaderAlreadyPaid": "Ji\u017e zaplaceno?", + "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", + "Items": "Polo\u017eky", + "OneChannel": "Jeden kan\u00e1l", + "ConfirmRemoveDownload": "Odebrat sta\u017een\u00ed?", + "RemoveDownload": "Odebrat sta\u017een\u00ed", + "KeepDownload": "Keep download", + "AddedOnValue": "P\u0159id\u00e1no {0}", + "RemovingFromDevice": "Odeb\u00edr\u00e1n\u00ed ze za\u0159\u00edzen\u00ed", + "KeepOnDevice": "Ponechat na za\u0159\u00edzen\u00ed", + "CancelDownload": "Zru\u0161it stahov\u00e1n\u00ed", + "SyncJobItemStatusReadyToTransfer": "P\u0159ipraveno k p\u0159enosu", + "SyncJobItemStatusSyncedMarkForRemoval": "Odeb\u00edr\u00e1n\u00ed ze za\u0159\u00edzen\u00ed", + "SyncJobItemStatusQueued": "P\u0159id\u00e1no do fronty", + "SyncJobItemStatusConverting": "Konverze", + "SyncJobItemStatusTransferring": "P\u0159en\u00e1\u0161en\u00ed", + "SyncJobItemStatusSynced": "Sta\u017eeno", + "SyncJobItemStatusFailed": "Selhalo", + "SyncJobItemStatusRemovedFromDevice": "Odebr\u00e1no ze za\u0159\u00edzen\u00ed", + "SyncJobItemStatusCancelled": "Zru\u0161eno", + "Retry": "Opakovat", + "HeaderMyDevice": "Moje za\u0159\u00edzen\u00ed", + "Continue": "Pokra\u010dovat", + "ContinueInSecondsValue": "Pokra\u010dovat za {0} sekund.", + "HeaderRemoteControl": "D\u00e1lkov\u00fd ovlada\u010d", + "Disconnect": "Odpojit", + "EnableDisplayMirroring": "Povolit zrcadlen\u00ed obrazu", + "HeaderPlayOn": "Play On", + "Quality": "Kvalita", + "Auto": "Automatizovat", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Pom\u011br stran", + "Original": "Origin\u00e1l", + "Fill": "Vyplnit", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "\u017d\u00e1dn\u00e9 servery nejsou k dispozici. Pokud jste byli pozv\u00e1ni na sd\u00edlen\u00fd server, ujist\u011bte se, \u017ee jste pozv\u00e1nku n\u00ed\u017ee akceptovali nebo klikly na odkaz v e-mailu.", + "MessagePlayAccessRestricted": "P\u0159ehr\u00e1v\u00e1n\u00ed tohoto obsahu je moment\u00e1ln\u011b omezeno. Pro v\u00edce informac\u00ed kontaktujte pros\u00edm Va\u0161eho spr\u00e1vce Emby Serveru.", + "Accept": "P\u0159ijmout", + "Reject": "Odm\u00edtnout", + "Connect": "P\u0159ipojit", + "HeaderMyMedia": "Moje m\u00e9dia", + "HeaderMyMediaSmall": "Moje m\u00e9dia (mal\u00e9)", + "LatestFromLibrary": "Nejnov\u011bj\u0161\u00ed {0}", + "ContinueWatching": "Pokra\u010dovat ve sledov\u00e1n\u00ed", + "HeaderLatestChannelMedia": "Nejnov\u011bj\u0161\u00ed polo\u017eky kan\u00e1lu", + "HeaderContinueWatching": "Pokra\u010dovat ve sledov\u00e1n\u00ed", + "HeaderContinueListening": "Pokra\u010dovat v poslechu", + "HeaderActiveRecordings": "Aktivn\u00ed nahr\u00e1v\u00e1n\u00ed", + "HeaderLatestRecordings": "Nejnov\u011bj\u0161\u00ed nahr\u00e1vky", + "LabelSyncTo": "Sync do:", + "LabelConvertTo": "Convert to:", + "Next": "Dal\u0161\u00ed", + "LabelSource": "Zdroj:", + "LabelVersion": "Verze:", + "AllLanguages": "V\u0161echny jazyky", + "Previous": "P\u0159edchoz\u00ed", + "HeaderNextUp": "Nadch\u00e1zej\u00edc\u00ed", + "HeaderLatestFrom": "Nejnov\u011bj\u0161\u00ed od {0}", + "LabelHomeScreenSectionValue": "Domovsk\u00e1 obrazovka sekce {0}", + "SettingsSaved": "Nastaven\u00ed ulo\u017eeno.", + "None": "\u017d\u00e1dn\u00fd", + "More": "V\u00edce", + "Up": "Nahoru", + "Down": "Dol\u016f", + "Home": "Dom\u016f", + "Favorites": "Obl\u00edben\u00e9", + "HeaderHomeScreen": "Domovsk\u00e1 obrazovka", + "HeaderLatestChannelItems": "Nejnov\u011bj\u0161\u00ed polo\u017eky kan\u00e1lu", + "HeaderLibraryOrder": "Po\u0159ad\u00ed knihovny", + "HideWatchedContentFromLatestMedia": "Skr\u00fdt p\u0159ehran\u00e9 polo\u017eky ze seznamu nejnov\u011bj\u0161\u00edch m\u00e9di\u00ed", + "HeaderOnNow": "Pr\u00e1v\u011b te\u010f", + "HeaderPlaybackError": "Chyba p\u0159ehr\u00e1v\u00e1n\u00ed", + "PlaybackErrorNotAllowed": "V sou\u010dasn\u00e9 dob\u011b nejste opr\u00e1vn\u011bni p\u0159ehr\u00e1vat tento obsah. Pro v\u00edce informac\u00ed se obra\u0165te se na spr\u00e1vce syst\u00e9mu.", + "PlaybackErrorNoCompatibleStream": "\u017d\u00e1dn\u00e9 kompatibiln\u00ed streamy nejsou v sou\u010dasn\u00e9 dob\u011b k dispozici. Zkuste to pros\u00edm pozd\u011bji nebo pro v\u00edce podrobnost\u00ed kontaktujte sv\u00e9ho spr\u00e1vce syst\u00e9mu", + "PlaybackErrorPlaceHolder": "Pro p\u0159ehr\u00e1n\u00ed videa nejd\u0159\u00edve vlo\u017ete disk", + "Guide": "Pr\u016fvodce", + "Suggestions": "N\u00e1vrhy", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Kolekce", + "LabelSelectFolderGroups": "Automaticky seskupit obsah z n\u00e1sleduj\u00edc\u00edch slo\u017eek do zobrazen\u00ed, jako jsou Filmy, Hudba a TV:", + "LabelSelectFolderGroupsHelp": "Slo\u017eky, kter\u00e9 nejsou za\u0161krtnuty budou zobrazeny ve vlastn\u00edm pohledu.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Seri\u00e1ly", + "HeaderLibraryFolders": "Slo\u017eky knihovny", + "HeaderTermsOfPurchase": "Podm\u00ednky n\u00e1kupu", + "PrivacyPolicy": "Z\u00e1sady ochrany osobn\u00edch \u00fadaj\u016f", + "TermsOfUse": "Podm\u00ednky pou\u017eit\u00ed", + "RepeatMode": "M\u00f3d opakov\u00e1n\u00ed", + "RepeatOne": "Opakovat jeden", + "RepeatAll": "Opakovat v\u0161e", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Chcete vypnout Emby na {0}?", + "Yes": "Ano", + "No": "Ne", + "LiveTV": "Live TV", + "Schedule": "Napl\u00e1nov\u00e1n\u00ed \u00falohy", + "Recordings": "Nahr\u00e1vky", + "MarkWatched": "Ozna\u010dit jako shl\u00e9dnut\u00e9", + "ScanForNewAndUpdatedFiles": "Vyhledat nov\u00e9 a aktualizovan\u00e9 soubory", + "DirectStreamHelp1": "M\u00e9dium je kompatibiln\u00ed se za\u0159\u00edzen\u00edm, pokud jde o rozli\u0161en\u00ed a typ m\u00e9dia (H.264, AC3, atd.), ale je v nekompatibiln\u00edm kontejneru (.mkv, .avi, .wmv, atd.). Video bude za b\u011bhu p\u0159ebaleno ne\u017e bude streamov\u00e1no do za\u0159\u00edzen\u00ed.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "P\u0159\u00edm\u00e9 p\u0159ehr\u00e1n\u00ed", + "DirectStreaming": "P\u0159\u00edm\u00e9 streamov\u00e1n\u00ed", + "Transcoding": "P\u0159ek\u00f3dov\u00e1n\u00ed", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video kodek nen\u00ed podporov\u00e1n", + "AudioCodecNotSupported": "Audio kodek nen\u00ed podporov\u00e1n", + "SubtitleCodecNotSupported": "Form\u00e1t titulk\u016f nen\u00ed podporov\u00e1n", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Kontejner nen\u00ed podporov\u00e1n", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Datov\u00fd tok audia nen\u00ed podporov\u00e1n", + "AudioChannelsNotSupported": "Audio kan\u00e1ly nejsou podporov\u00e1ny", + "VideoResolutionNotSupported": "Rozli\u0161en\u00ed videa nen\u00ed podporov\u00e1no", + "AudioProfileNotSupported": "Audio profil nen\u00ed podporov\u00e1n", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Prokl\u00e1dan\u00e9 video nen\u00ed podporov\u00e1no", + "SecondaryAudioNotSupported": "P\u0159ep\u00edn\u00e1n\u00ed audio stopy nen\u00ed podporov\u00e1no", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby \u00fa\u010det odebr\u00e1n", + "MessageEmbyAccontRemoved": "\u00da\u010det Emby byl odstran\u011bn pro tohoto u\u017eivatele.", + "HeaderInvitationSent": "Pozv\u00e1nka odesl\u00e1na", + "MessageInvitationSentToUser": "E-mail byl odesl\u00e1n na adresu {0} a p\u0159ijmut\u00edm t\u00e9to pozvn\u00e1nky akceptujete va\u0161\u00ed pozv\u00e1nku ke sd\u00edlen\u00ed.", + "MessageInvitationSentToNewUser": "E-mail byl odesl\u00e1n na adresu {0} s v\u00fdzvou k registraci s Emby.", + "GuestUserNotFound": "U\u017eivatel nenalezen. Pros\u00edm, ujist\u011bte se, \u017ee n\u00e1zev je spr\u00e1vn\u00fd a zkuste to znovu, nebo zkuste zadat jejich e-mailovou adresu.", + "ErrorReachingEmbyConnect": "Do\u0161lo k chyb\u011b p\u0159i nav\u00e1z\u00e1n\u00ed spojen\u00ed k serveru Emby Connect. Ujist\u011bte se, zda je funk\u010dn\u00ed p\u0159ipojen\u00ed k internetu a zkuste to znovu.", + "ErrorAddingEmbyConnectAccount1": "Nastala chyba p\u0159i p\u0159id\u00e1v\u00e1n\u00ed \u00fa\u010dtu Emby Connect. Opravdu m\u00e1te vytvo\u0159en \u00fa\u010det u Emby? P\u0159ihlaste se zde {0}.", + "ErrorAddingEmbyConnectAccount2": "Pokud st\u00e1le m\u00e1te probl\u00e9my, po\u0161lete pros\u00edm e-mail na adresu {0} z e-mailov\u00e9 adresy pou\u017eit\u00e9 na \u00fa\u010dtu Emby.", + "ErrorAddingGuestAccount1": "Do\u0161lo k chyb\u011b p\u0159i p\u0159id\u00e1v\u00e1n\u00ed \u00fa\u010dtu Emby Connect. M\u00e1 v\u00e1\u0161 host vytvo\u0159en\u00fd \u00fa\u010det Emby? M\u016f\u017ee se p\u0159ihl\u00e1sit na {0}.", + "ErrorAddingGuestAccount2": "Pokud st\u00e1le m\u00e1te probl\u00e9my, po\u0161lete pros\u00edm e-mail na adresu {0} a p\u0159ilo\u017ete Va\u0161i i jejich e-mailovou adresu.", + "MessageEmbyAccountAdded": "Emby \u00fa\u010det byl p\u0159id\u00e1no k tomuto u\u017eivateli.", + "MessagePendingEmbyAccountAdded": "\u00da\u010det Emby byl p\u0159id\u00e1n pro tohoto u\u017eivatele. E-mail bude zasl\u00e1n majiteli \u00fa\u010dtu. Pozv\u00e1nku bude nutn\u00e9 potvrdit kliknut\u00edm na odkaz uvnit\u0159 e-mailu.", + "HeaderEmbyAccountAdded": "Emby \u00fa\u010det p\u0159id\u00e1n", + "LabelSubtitlePlaybackMode": "M\u00f3d titulk\u016f:", + "ErrorDeletingItem": "Nastala chyba p\u0159i maz\u00e1n\u00ed polo\u017eky z Emby Serveru. Zkontrolujte pros\u00edm, \u017ee Emby Server m\u00e1 opr\u00e1vn\u011bn\u00ed k z\u00e1pisu do slo\u017eky m\u00e9di\u00ed a zkuste to pros\u00edm znovu.", + "NoSubtitles": "\u017d\u00e1dn\u00e9 titulky", + "Default": "V\u00fdchoz\u00ed", + "Absolute": "Absolute", + "Smart": "Chytr\u00fd", + "Small": "Mal\u00fd", + "Smaller": "Smaller", + "Medium": "St\u0159edn\u00ed", + "Large": "Velk\u00fd", + "ExtraLarge": "Extra velk\u00fd", + "OnlyForcedSubtitles": "Pouze vynucen\u00e9 titulky", + "AlwaysPlaySubtitles": "V\u017edy zobrazit titulky", + "DefaultSubtitlesHelp": "Titulky jsou na\u010dteny na z\u00e1klad\u011b v\u00fdchoz\u00edch a vynucen\u00fdch nastaven\u00ed ve vlo\u017een\u00fdch metadatech. Jazykov\u00e9 preference jsou vzaty v \u00favahu, pokud je k dispozici v\u00edce mo\u017enost\u00ed.", + "SmartSubtitlesHelp": "Titulky budou na\u010dteny po porovn\u00e1n\u00ed s preferovan\u00fdm jazykem, pokud je zvuk v ciz\u00edm jazyce.", + "HeaderSubtitleSettings": "Nastaven\u00ed titulk\u016f", + "HeaderSubtitleAppearance": "Vzhled titulk\u016f", + "OnlyForcedSubtitlesHelp": "Jen vynucen\u00e9 titulky budou nahr\u00e1ny.", + "AlwaysPlaySubtitlesHelp": "Titulky odpov\u00eddaj\u00edc\u00ed jazykov\u00e9 p\u0159edvolb\u011b se na\u010dtou bez ohledu na jazyk audia.", + "NoSubtitlesHelp": "Ve v\u00fdchoz\u00edm nastaven\u00ed nebudou titulky na\u010dteny. B\u011bhem p\u0159ehr\u00e1v\u00e1n\u00ed v\u0161ak mohou b\u00fdt manu\u00e1ln\u011b zapnuty.", + "LabelPreferredSubtitleLanguage": "Preferovan\u00fd jazyk titulk\u016f:", + "LabelTextSize": "Velikost textu:", + "TheseSettingsAffectSubtitlesOnThisDevice": "Tato nastaven\u00ed ovlivn\u00ed titulky na tomto za\u0159\u00edzen\u00ed", + "LabelDropShadow": "Vrhat st\u00edn:", + "LabelTextBackgroundColor": "Barva pozad\u00ed textu:", + "LabelWindowBackgroundColor": "Barva pozad\u00ed textu:", + "LabelFont": "P\u00edsmo:", + "LabelTextColor": "Barva textu:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Vrhat st\u00edn", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Norm\u00e1ln\u00ed", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "\u010cek\u00e1n\u00ed na Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "St\u00e1hnout nastaven\u00ed", + "Hide": "Skr\u00fdt", + "HeaderStartNow": "Za\u010d\u00edt te\u010f", + "HeaderNextVideoPlayingInValue": "P\u0159ehr\u00e1v\u00e1n\u00ed dal\u0161\u00edho videa za {0}", + "HeaderNextEpisodePlayingInValue": "P\u0159ehr\u00e1v\u00e1n\u00ed dal\u0161\u00ed epizody za {0}", + "HeaderSecondsValue": "{0} sekund", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profil nen\u00ed podporov\u00e1n", + "VideoFramerateNotSupported": "Sn\u00edmkov\u00e1 frekvence videa nen\u00ed podporov\u00e1na", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Zastavit nahr\u00e1v\u00e1n\u00ed", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Spravovat nahr\u00e1v\u00e1n\u00ed", + "LabelDropImageHere": "Sem p\u0159et\u00e1hn\u011bte obr\u00e1zek nebo klikn\u011bte pro proch\u00e1zen\u00ed.", + "MessageFileReadError": "Do\u0161lo k chyb\u011b p\u0159i \u010dten\u00ed souboru. Pros\u00edm zkuste to znovu.", + "Browse": "Proch\u00e1zet", + "HeaderUploadImage": "Nahr\u00e1t obr\u00e1zek", + "HeaderAddUpdateImage": "P\u0159idat\/Aktualizovat obr\u00e1zek", + "LabelImageType": "Typ obr\u00e1zku:", + "Upload": "Nahr\u00e1t", + "Primary": "Prim\u00e1rn\u00ed", + "Art": "Um\u011bn\u00ed", + "Backdrop": "Pozad\u00ed", + "Banner": "Banner", + "Box": "Pouzdro", + "BoxRear": "Zadn\u00ed \u010d\u00e1st pouzdra", + "Disc": "Disk", + "Logo": "Logo", + "Menu": "Nab\u00eddka", + "Screenshot": "Sn\u00edmek obrazovky", + "Thumb": "Miniatura", + "ValueSeconds": "{0} sekund", + "HeaderAudioSettings": "Nastaven\u00ed zvuku", + "LabelAudioLanguagePreference": "Preferovan\u00fd jazyk zvuku:", + "LabelPlayDefaultAudioTrack": "P\u0159ehr\u00e1vat defaultn\u00ed audio stopu bez ohledu na jazyk", + "HeaderVideoQuality": "Kvalita videa", + "CinemaModeConfigurationHelp": "Re\u017eim Cinema p\u0159in\u00e1\u0161\u00ed z\u00e1\u017eitky jako z kina p\u0159\u00edmo do va\u0161eho ob\u00fdvac\u00edho pokoje s mo\u017enost\u00ed p\u0159ehr\u00e1t trailery a vlastn\u00ed intra p\u0159ed hlavn\u00edm programem.", + "EnableNextVideoInfoOverlay": "Povolit informaci o n\u00e1sleduj\u00edc\u00edm videu b\u011bhem p\u0159ehr\u00e1v\u00e1n\u00ed", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Automaticky p\u0159ehr\u00e1vat dal\u0161\u00ed epizodu", + "LabelMaxChromecastBitrate": "Maxim\u00e1ln\u00ed datov\u00fd tok pro Chromecast:", + "LabelSkipBackLength": "D\u00e9lka posunu zp\u011bt:", + "LabelSkipForwardLength": "D\u00e9lka posunu vp\u0159ed:", + "EnableCinemaMode": "Povolit Cinema M\u00f3d", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Kvalita hudby", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Nejnov\u011bj\u0161\u00ed m\u00e9dia", + "HeaderRestartingEmbyServer": "Restartov\u00e1n\u00ed Emby serveru", + "RestartPleaseWaitMessage": "Po\u010dkejte pros\u00edm, ne\u017e se Emby Server vypne a restartuje. M\u016f\u017ee to trvat p\u00e1r minut.", + "PlayNext": "P\u0159ehr\u00e1t dal\u0161\u00ed", + "AllowSeasonalThemes": "Povolit automatick\u00e1 sez\u00f3nn\u00ed t\u00e9mata", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Zvuk:", + "LabelVideo": "Video:", + "LabelSubtitles": "Titulky:", + "Off": "Vypnuto", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/da.json b/src/bower_components/emby-webcomponents/strings/da.json index 1f3081bce2..d601bd725e 100644 --- a/src/bower_components/emby-webcomponents/strings/da.json +++ b/src/bower_components/emby-webcomponents/strings/da.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Godkend", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Skuespiller", - "Add": "Tilføj", - "AddToCollection": "Tilføj til samling", - "AddToPlayQueue": "Tilføj til afspilningskø", - "AddToPlaylist": "Tilføj til afspilningsliste", - "AddedOnValue": "Tilføjet {0}", - "Advanced": "Avanceret", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "Alle kanaler", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Alle episoder", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Altid", - "AroundTime": "Omkring {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "Så mange som muligt", - "Ascending": "Ascending", - "AspectRatio": "Billedformat", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "Ny", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Bedste tilpasning", - "BirthLocation": "Fødselslokation", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Annuller", - "ButtonGotIt": "Forstået", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Afspil Ét Minut", - "ButtonRestart": "Genstart", - "ButtonRestorePreviousPurchase": "Genskab Indkøb", - "ButtonTryAgain": "Prøv Igen", - "ButtonUnlockPrice": "Lås op for {0}", - "ButtonUnlockWithPurchase": "Lås op for med Køb", - "CancelDownload": "Annuller download", - "CancelRecording": "Annuller optagelse", - "CancelSeries": "Annuller serie", - "Categories": "Kategorier", - "ChannelNameOnly": "Udelukkende kanal {0}", - "ChannelNumber": "Kanalnummer", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Biograftilstand giver dig den ægte biografoplevelse med trailers og brugertilpassede introer, før selve filmen.", - "CloudSyncFeatureDescription": "Synk dine medier til skyen for nem backup, arkivering og konvertering.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Komponist", - "ConfigureDateAdded": "Konfigurer hvordan tilføjet-dato bestemmes, under Jellyfin Server-kontrolpanelet under Biblioteksindstillinger", - "ConfirmDeleteImage": "Slet billede?", - "ConfirmDeleteItem": "Hvis dette element slettes, fjernes det både fra dit filsystem samt din mediebibliotek. Er du sikker på du ønsker at fortsætte?", - "ConfirmDeleteItems": "Sletning af disse emner vil både fjerne dem fra filsystemet og dit mediebibliotek. Er du sikker på at du vil fortsætte?", - "ConfirmDeletion": "Bekræft sletning", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Fjern download?", - "Connect": "Forbind", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Fortsæt", - "ContinueInSecondsValue": "Fortsæt om {0} sekunder.", - "ContinueWatching": "Continue watching", - "Continuing": "Forsættes", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Lande", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Dage", - "Default": "Default", - "DefaultErrorMessage": "Det opstod en fejl ved behandlingen af forespørgslen. Prøv igen senere.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Slet", - "DeleteMedia": "Slet medie", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Instruktør", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Afbryd", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Optag ikke", - "Down": "Down", - "Download": "Hent", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR påkræver et aktivt Jellyfin Premiere abonnement.", - "Edit": "Rediger", - "EditImages": "Rediger billeder", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Rediger undertekster", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Aktiver biograftilstand", - "EnableColorCodedBackgrounds": "Aktiver farvekodet baggrunde", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Færdig", - "EndsAtValue": "Slutter {0}", - "Episodes": "Episodes", - "Error": "Fejl", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorit", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "Denne funktion kræver et aktivt Jellyfin Premiere abonnement.", - "Features": "Features", - "File": "Fil", - "Fill": "Udfyld", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "God fornøjelse med gratis adgang til Jellyfin apps til dine enheder.", - "Friday": "Fredag", - "GenreValue": "Genre: {0}", - "Genres": "Genre", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Grupér versioner", - "GuestStar": "Gæsteskuespiller", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD-programmer", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Tilføj til samling", - "HeaderAddToPlaylist": "Tilføj til afspilningsliste", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Allerede Betalt?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Få Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Fordele ved Jellyfin Premiere", - "HeaderCancelRecording": "Annuller Optagelse", - "HeaderCancelSeries": "Annuller Serie", - "HeaderCinemaMode": "Biograftilstand", - "HeaderCloudSync": "Sky-Synk", - "HeaderConfirmRecordingCancellation": "Bekræft annullering af optagelse", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Konverter Dine Optagelser", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Slet element", - "HeaderDeleteItems": "Slet emner", - "HeaderDisplaySettings": "Visningsindstillinger", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Rediger billeder", - "HeaderEnabledFields": "Aktivér Felter", - "HeaderEnabledFieldsHelp": "Fjern fluebenet fra et felt for at låse det og forhindre dets data fra at blive ændret.", - "HeaderExternalIds": "Eksterne ID'er:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Gratis Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Indtast et eller flere søgekriterier.Fjern kriterier for at få flere søgeresultater.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Bevar Optagelse", - "HeaderKeepSeries": "Bevar Serie", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Lær Mere", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Indstillinger for metadata", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "Min Enhed", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "Ny optagelse", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Medie", - "HeaderOfflineDownloadsDescription": "Download medier til dine enheder for nem offline-brug.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Afspil mit Medie", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Fejl i afspilning", - "HeaderRecordingOptions": "Optagelsesindstillinger", - "HeaderRemoteControl": "Fjernbetjening", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Sig noget i stil med...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Vælg dato", - "HeaderSeriesOptions": "Serieindstillinger", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Information om specialepisoder", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Prøv Afspilning", - "HeaderUnlockFeature": "Lås op for Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "Du sagde...", - "Help": "Hjælp", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "Hvordan betalte du?", - "IHaveJellyfinPremiere": "Jeg har Jellyfin Premiere", - "IPurchasedThisApp": "Jeg købte denne app", - "Identify": "Identificer", - "Images": "Billeder", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installerer {0}", - "InstantMix": "Instant Mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} elementer", - "Items": "emner", - "KeepDownload": "Keep download", - "KeepOnDevice": "Bevar på enhed", - "Kids": "Børn", - "Label3DFormat": "3D format:", - "LabelAirDays": "Sendedage:", - "LabelAirTime": "Sendetid:", - "LabelAirsAfterSeason": "Sendes efter sæson:", - "LabelAirsBeforeEpisode": "Sendes før episode:", - "LabelAirsBeforeSeason": "Sendes før sæson:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Albumartister:", - "LabelArtists": "Artister:", - "LabelArtistsHelp": "Angiv flere ved at sætte ; mellem dem.", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Fødselsdato:", - "LabelBirthYear": "Fødselsår:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Kanaler:", - "LabelCollection": "Samling:", - "LabelCommunityRating": "Fællesskabsvurdering:", - "LabelContentType": "Indholdstype:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Land:", - "LabelCriticRating": "Kritikervurdering:", - "LabelCustomRating": "Brugerdefineret bedømmelse:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Dato for tilføjelse:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Dødsdato:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disk-nummer", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Visningsorden:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "Email-adresse:", - "LabelEndDate": "Slutdato:", - "LabelEpisodeNumber": "Episodenummer:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Maks. filer:", - "LabelKeep:": "Bevar:", - "LabelKeepUpTo": "Bevar op til:", - "LabelLanguage": "Sprog:", - "LabelLockItemToPreventChanges": "Lås for at undgå fremtidige ændringer", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Foretrukket sprog for nedhentning:", - "LabelName": "Navn:", - "LabelNumber": "Nummer:", - "LabelOriginalAspectRatio": "Originalt formatforhold:", - "LabelOriginalTitle": "Original titel:", - "LabelOverview": "Oversigt:", - "LabelParentNumber": "Forældre-nummer:", - "LabelParentalRating": "Aldersgrænse:", - "LabelPath": "Sti:", - "LabelPersonRole": "Rolle:", - "LabelPersonRoleHelp": "Eksempel: Isbilschauffør", - "LabelPlaceOfBirth": "Fødselssted:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Afspilningsliste:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profil:", - "LabelQuality": "Kvalitet:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Optag:", - "LabelRefreshMode": "Genopfrisk tilstand:", - "LabelReleaseDate": "Udgivelsesdato:", - "LabelRuntimeMinutes": "Spilletid (minutter):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Sæsonnummer:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Kort oversigt:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sortér titel:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start når muligt:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop når muligt:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Navn til synkroniserings job:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Synkroniser til:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Titel:", - "LabelTrackNumber": "Spor nummer:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Hjemmeside:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Lær mere", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live-udsending", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Markér som afspillet", - "MarkUnplayed": "Markér som ikke afspillet", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Et aktivt Jellyfin Premiere abonnement er nødvendigt for at oprette automatiserede optagelser af serier.", - "MessageAreYouSureDeleteSubtitles": "Er du sikker på du ønsker at slette denne undertekstfil?", - "MessageConfirmRecordingCancellation": "Er du sikker på du ønsker at annullere denne optagelse?", - "MessageDownloadQueued": "Download sat i kø.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "Hvis du afslog adgang til tale for appen, skal du re-konfigurere før du prøver igen.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Element gemt.", - "MessageItemsAdded": "Emne tilføjet.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Efterlad tom for at arve indstillinger fra en overliggende post eller den globale standardværdi.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "Hvis du har et aktivt Jellyfin Premiere abonnement, skal du være sikker på at Jellyfin Premiere er konfigureret i dit Jellyfin Server-kontrolpanel, som kan tilgåes ved at klikke på Jellyfin Premiere i hovedmenuen.", - "MessageUnlockAppWithPurchaseOrSupporter": "Lås op for dette feature med en lille enkeltstående betaling, eller med et aktivt Jellyfin Premiere abonnement.", - "MessageUnlockAppWithSupporter": "Lås op for dette feature med et aktivt Jellyfin Premiere abonnement.", - "MessageWeDidntRecognizeCommand": "Beklager, men vi genkendte ikke denne kommando.", - "MinutesAfter": "minutter efter", - "MinutesBefore": "minutter før", - "Mobile": "Mobile / Tablet", - "Monday": "Mandag", - "More": "More", - "MoveLeft": "Flyt mod venstre", - "MoveRight": "Flyt mod højre", - "Movies": "Film", - "MySubtitles": "Mine Undertekster", - "Name": "Navn", - "NewCollection": "Ny samling", - "NewCollectionHelp": "Samlinger lader dig oprette personaliserede grupper af film og andet biblioteksindhold.", - "NewCollectionNameExample": "Eksempel: Star Wars samling", - "NewEpisodes": "Nye episoder", - "NewEpisodesOnly": "Kun nye episoder", - "News": "Nyheder", - "Next": "Next", - "No": "No", - "NoItemsFound": "Ingen emner fundet.", - "NoSubtitleSearchResultsFound": "Ingen resultater fundet.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "En kanal", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Åben", - "OptionNew": "Ny...", - "Original": "Standard", - "OriginalAirDateValue": "Originalt sendt: {0}", - "Overview": "Overblik", - "PackageInstallCancelled": "{0} installation afbrudt.", - "PackageInstallCompleted": "{0} installation udført.", - "PackageInstallFailed": "{0} installationen mislykkedes.", - "ParentalRating": "Parental Rating", - "People": "Personer", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Placer favoritkanaler i begyndelsen", - "Play": "Afspil", - "PlayAllFromHere": "Afspil alt fra her", - "PlayCount": "Play count", - "PlayFromBeginning": "Afspil fra begyndelsen", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Afspillet", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Indtast venligst et navn eller eksternt Id.", - "PleaseRestartServerName": "Genstart venligst Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Vælg venligst mindst to elementer.", - "Premiere": "Premiere", - "Premieres": "Premiere", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producent", - "ProductionLocations": "Produktionslokationer", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Konverter automatisk optagelser til streaming-venlige formater med Jellyfin Premiere. Optagelser bliver konverteret on-the-fly til MP4 eller MKV, afhængigt af dine Jellyfin serverindstillinger.", - "Quality": "Kvalitet", - "QueueAllFromHere": "Set alt her i kø", - "Raised": "Raised", - "RecentlyWatched": "Nyligt sete", - "Record": "Optag", - "RecordSeries": "Optag serie", - "RecordingCancelled": "Optagelse annulleret.", - "RecordingScheduled": "Optagelse planlagt.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Opdater", - "RefreshDialogHelp": "Metadata opdateres alt efter hvilke indstillinger og internet-servicer der er aktiveret i Jellyfin Server-kontrolpanelet.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Opdatering sat i kø", - "Reject": "Afvis", - "ReleaseDate": "Udgivelsesdato", - "RemoveDownload": "Fjern download", - "RemoveFromCollection": "Fjern fra samling", - "RemoveFromPlaylist": "Fjer fra afspilningsliste", - "RemovingFromDevice": "Fjerner fra enhed", - "Repeat": "Gentag", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Gentag episoder", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Erstat alle metadata", - "ReplaceExistingImages": "Erstat eksisterende billeder", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Genoptag fra {0}", - "Retry": "Prøv igen", - "RunAtStartup": "Run at startup", - "Runtime": "Afspilningstid", - "Saturday": "Lørdag", - "Save": "Gem", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Skærmbilleder", - "Search": "Søg", - "SearchForCollectionInternetMetadata": "Søg på internettet efter billeder og metadata", - "SearchForMissingMetadata": "Søg efter manglende metadata", - "SearchForSubtitles": "Søg efter undertekster", - "SearchResults": "Søgeresultater", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Serie annulleret.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Optagning af serie planlagt.", - "SeriesSettings": "Serieindstillinger", - "SeriesYearToPresent": "{0} - Nuværende", - "ServerNameIsRestarting": "Jellyfin Server - {0} genstarter.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} lukker ned.", - "ServerUpdateNeeded": "Denne Jellyfin server bør opdateres. For at downloade den nyeste version besøg venligst {0}", - "Settings": "Indstillinger", - "SettingsSaved": "Settings saved.", - "Share": "Del", - "ShowIndicatorsFor": "Vis indikatorer for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Bland", - "SkipEpisodesAlreadyInMyLibrary": "Optag ikke episoder som allerede findes i mit bibliotek", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episoder bliver sammenlignet på sæson og episodenummer, når muligt.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sortér kanaler efter:", - "SortName": "Sorteringsnavn", - "Sports": "Sport", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studier", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Undertekster", - "Suggestions": "Suggestions", - "Sunday": "Søndag", - "Sync": "Synk", - "SyncJobItemStatusCancelled": "Annulleret", - "SyncJobItemStatusConverting": "Konverterer", - "SyncJobItemStatusFailed": "Fejlet", - "SyncJobItemStatusQueued": "Sat i kø", - "SyncJobItemStatusReadyToTransfer": "Klar til at Overføre", - "SyncJobItemStatusRemovedFromDevice": "Fjern fra enhed", - "SyncJobItemStatusSynced": "Downloadet", - "SyncJobItemStatusSyncedMarkForRemoval": "Fjerner fra enhed", - "SyncJobItemStatusTransferring": "Overfører", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Nyd venligst et minuts afspilning. Tak fordi du prøver Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Torsdag", - "TrackCount": "{0} numre", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Prøv Multi-Valg", - "TryMultiSelectMessage": "For at redigere adskillige emner, skal du blot klikke og holde på hvilken som helst plakat og vælge de emner du vil administrere. Prøv det!", - "Tuesday": "Tirsdag", - "Uniform": "Uniform", - "UnlockGuide": "Oplås guide", - "Unplayed": "Unplayed", - "Unrated": "Ingen bedømmelse", - "UntilIDelete": "Til jeg sletter", - "UntilSpaceNeeded": "Til pladsen er nødvendig", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} album", - "ValueDiscNumber": "Disk {0}", - "ValueEpisodeCount": "{0} episoder", - "ValueGameCount": "{0} spil", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} film", - "ValueMusicVideoCount": "{0} musikvideoer", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 spil", - "ValueOneItem": "1 emne", - "ValueOneMovie": "1 film", - "ValueOneMusicVideo": "1 musikvideo", - "ValueOneSeries": "1 serie", - "ValueOneSong": "1 sang", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} serier", - "ValueSongCount": "{0} sange", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "Vis album", - "ViewArtist": "Vis kunstner", - "VoiceInput": "Taleinput", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Onsdag", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Forfatter", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "L\u00e5s op for dette feature med en lille enkeltst\u00e5ende betaling, eller med et aktivt Emby Premiere abonnement.", + "MessageUnlockAppWithSupporter": "L\u00e5s op for dette feature med et aktivt Emby Premiere abonnement.", + "MessageToValidateSupporter": "Hvis du har et aktivt Emby Premiere abonnement, skal du v\u00e6re sikker p\u00e5 at Emby Premiere er konfigureret i dit Emby Server-kontrolpanel, som kan tilg\u00e5es ved at klikke p\u00e5 Emby Premiere i hovedmenuen.", + "ValueSpecialEpisodeName": "Special - {0}", + "Share": "Del", + "Add": "Tilf\u00f8j", + "ServerUpdateNeeded": "Denne Emby server b\u00f8r opdateres. For at downloade den nyeste version bes\u00f8g venligst {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "Ny", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Gentag", + "TrackCount": "{0} numre", + "ItemCount": "{0} elementer", + "OriginalAirDateValue": "Originalt sendt: {0}", + "EndsAtValue": "Slutter {0}", + "HeaderSelectDate": "V\u00e6lg dato", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Afspillet", + "ButtonOk": "Ok", + "ButtonCancel": "Annuller", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Forst\u00e5et", + "ButtonRestart": "Genstart", + "RecordingCancelled": "Optagelse annulleret.", + "SeriesCancelled": "Serie annulleret.", + "RecordingScheduled": "Optagelse planlagt.", + "SeriesRecordingScheduled": "Optagning af serie planlagt.", + "HeaderNewRecording": "Ny optagelse", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "S\u00f8ndag", + "Monday": "Mandag", + "Tuesday": "Tirsdag", + "Wednesday": "Onsdag", + "Thursday": "Torsdag", + "Friday": "Fredag", + "Saturday": "L\u00f8rdag", + "Days": "Dage", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Optag serie", + "HeaderCinemaMode": "Biograftilstand", + "HeaderCloudSync": "Sky-Synk", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "HeaderOfflineDownloads": "Offline Medie", + "HeaderOfflineDownloadsDescription": "Download medier til dine enheder for nem offline-brug.", + "CloudSyncFeatureDescription": "Synk dine medier til skyen for nem backup, arkivering og konvertering.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "CinemaModeFeatureDescription": "Biograftilstand giver dig den \u00e6gte biografoplevelse med trailers og brugertilpassede introer, f\u00f8r selve filmen.", + "HeaderFreeApps": "Gratis Emby Apps", + "FreeAppsFeatureDescription": "God forn\u00f8jelse med gratis adgang til Emby apps til dine enheder.", + "HeaderBecomeProjectSupporter": "F\u00e5 Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Et aktivt Emby Premiere abonnement er n\u00f8dvendigt for at oprette automatiserede optagelser af serier.", + "LabelEmailAddress": "Email-adresse:", + "PromoConvertRecordingsToStreamingFormat": "Konverter automatisk optagelser til streaming-venlige formater med Emby Premiere. Optagelser bliver konverteret on-the-fly til MP4 eller MKV, afh\u00e6ngigt af dine Emby serverindstillinger.", + "FeatureRequiresEmbyPremiere": "Denne funktion kr\u00e6ver et aktivt Emby Premiere abonnement.", + "HeaderConvertYourRecordings": "Konverter Dine Optagelser", + "Record": "Optag", + "Save": "Gem", + "Edit": "Rediger", + "Download": "Hent", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Avanceret", + "Delete": "Slet", + "HeaderDeleteItem": "Slet element", + "ConfirmDeleteItem": "Hvis dette element slettes, fjernes det b\u00e5de fra dit filsystem samt din mediebibliotek. Er du sikker p\u00e5 du \u00f8nsker at forts\u00e6tte?", + "Refresh": "Opdater", + "RefreshQueued": "Opdatering sat i k\u00f8", + "AddToCollection": "Tilf\u00f8j til samling", + "HeaderAddToCollection": "Tilf\u00f8j til samling", + "NewCollection": "Ny samling", + "LabelCollection": "Samling:", + "Help": "Hj\u00e6lp", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Samlinger lader dig oprette personaliserede grupper af film og andet biblioteksindhold.", + "SearchForCollectionInternetMetadata": "S\u00f8g p\u00e5 internettet efter billeder og metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Navn:", + "NewCollectionNameExample": "Eksempel: Star Wars samling", + "MessageItemsAdded": "Emne tilf\u00f8jet.", + "OptionNew": "Ny...", + "LabelPlaylist": "Afspilningsliste:", + "AddToPlaylist": "Tilf\u00f8j til afspilningsliste", + "HeaderAddToPlaylist": "Tilf\u00f8j til afspilningsliste", + "Subtitles": "Undertekster", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "S\u00f8g efter undertekster", + "LabelLanguage": "Sprog:", + "Search": "S\u00f8g", + "NoSubtitleSearchResultsFound": "Ingen resultater fundet.", + "File": "Fil", + "MessageAreYouSureDeleteSubtitles": "Er du sikker p\u00e5 du \u00f8nsker at slette denne undertekstfil?", + "ConfirmDeletion": "Bekr\u00e6ft sletning", + "MySubtitles": "Mine Undertekster", + "MessageDownloadQueued": "Download sat i k\u00f8.", + "EditSubtitles": "Rediger undertekster", + "UnlockGuide": "Opl\u00e5s guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Erstat eksisterende billeder", + "ReplaceAllMetadata": "Erstat alle metadata", + "SearchForMissingMetadata": "S\u00f8g efter manglende metadata", + "LabelRefreshMode": "Genopfrisk tilstand:", + "NoItemsFound": "Ingen emner fundet.", + "HeaderSaySomethingLike": "Sig noget i stil med...", + "ButtonTryAgain": "Pr\u00f8v Igen", + "HeaderYouSaid": "Du sagde...", + "MessageWeDidntRecognizeCommand": "Beklager, men vi genkendte ikke denne kommando.", + "MessageIfYouBlockedVoice": "Hvis du afslog adgang til tale for appen, skal du re-konfigurere f\u00f8r du pr\u00f8ver igen.", + "ValueDiscNumber": "Disk {0}", + "Unrated": "Ingen bed\u00f8mmelse", + "Favorite": "Favorit", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata opdateres alt efter hvilke indstillinger og internet-servicer der er aktiveret i Emby Server-kontrolpanelet.", + "Open": "\u00c5ben", + "Play": "Afspil", + "AddToPlayQueue": "Tilf\u00f8j til afspilningsk\u00f8", + "Shuffle": "Bland", + "Identify": "Identificer", + "EditImages": "Rediger billeder", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Synk", + "InstantMix": "Instant Mix", + "ViewAlbum": "Vis album", + "ViewArtist": "Vis kunstner", + "QueueAllFromHere": "Set alt her i k\u00f8", + "PlayAllFromHere": "Afspil alt fra her", + "PlayFromBeginning": "Afspil fra begyndelsen", + "ResumeAt": "Genoptag fra {0}", + "RemoveFromPlaylist": "Fjer fra afspilningsliste", + "RemoveFromCollection": "Fjern fra samling", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark\u00e9r som afspillet", + "MarkUnplayed": "Mark\u00e9r som ikke afspillet", + "GroupVersions": "Grup\u00e9r versioner", + "PleaseSelectTwoItems": "V\u00e6lg venligst mindst to elementer.", + "TryMultiSelect": "Pr\u00f8v Multi-Valg", + "TryMultiSelectMessage": "For at redigere adskillige emner, skal du blot klikke og holde p\u00e5 hvilken som helst plakat og v\u00e6lge de emner du vil administrere. Pr\u00f8v det!", + "HeaderConfirmRecordingCancellation": "Bekr\u00e6ft annullering af optagelse", + "MessageConfirmRecordingCancellation": "Er du sikker p\u00e5 du \u00f8nsker at annullere denne optagelse?", + "Error": "Fejl", + "VoiceInput": "Taleinput", + "LabelContentType": "Indholdstype:", + "LabelPath": "Sti:", + "Playlists": "Playlists", + "LabelTitle": "Titel:", + "LabelOriginalTitle": "Original titel:", + "LabelSortTitle": "Sort\u00e9r titel:", + "LabelDateAdded": "Dato for tilf\u00f8jelse:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Konfigurer hvordan tilf\u00f8jet-dato bestemmes, under Emby Server-kontrolpanelet under Biblioteksindstillinger", + "LabelStatus": "Status:", + "LabelArtists": "Artister:", + "LabelArtistsHelp": "Angiv flere ved at s\u00e6tte ; mellem dem.", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Albumartister:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "F\u00e6llesskabsvurdering:", + "LabelCriticRating": "Kritikervurdering:", + "CriticRating": "Critic rating", + "LabelWebsite": "Hjemmeside:", + "LabelTagline": "Tagline:", + "LabelOverview": "Oversigt:", + "LabelShortOverview": "Kort oversigt:", + "LabelReleaseDate": "Udgivelsesdato:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "F\u00f8dselssted:", + "Aired": "Aired", + "LabelAirDays": "Sendedage:", + "LabelAirTime": "Sendetid:", + "LabelRuntimeMinutes": "Spilletid (minutter):", + "LabelParentalRating": "Aldersgr\u00e6nse:", + "LabelCustomRating": "Brugerdefineret bed\u00f8mmelse:", + "LabelOriginalAspectRatio": "Originalt formatforhold:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Information om specialepisoder", + "LabelAirsBeforeSeason": "Sendes f\u00f8r s\u00e6son:", + "LabelAirsAfterSeason": "Sendes efter s\u00e6son:", + "LabelAirsBeforeEpisode": "Sendes f\u00f8r episode:", + "HeaderExternalIds": "Eksterne ID'er:", + "HeaderDisplaySettings": "Visningsindstillinger", + "LabelDisplayOrder": "Visningsorden:", + "Display": "Display", + "Countries": "Lande", + "Genres": "Genre", + "Studios": "Studier", + "Tags": "Tags", + "HeaderMetadataSettings": "Indstillinger for metadata", + "People": "Personer", + "LabelMetadataDownloadLanguage": "Foretrukket sprog for nedhentning:", + "LabelLockItemToPreventChanges": "L\u00e5s for at undg\u00e5 fremtidige \u00e6ndringer", + "MessageLeaveEmptyToInherit": "Efterlad tom for at arve indstillinger fra en overliggende post eller den globale standardv\u00e6rdi.", + "LabelCountry": "Land:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "F\u00f8dsels\u00e5r:", + "LabelBirthDate": "F\u00f8dselsdato:", + "LabelDeathDate": "D\u00f8dsdato:", + "LabelEndDate": "Slutdato:", + "LabelSeasonNumber": "S\u00e6sonnummer:", + "LabelEpisodeNumber": "Episodenummer:", + "LabelTrackNumber": "Spor nummer:", + "LabelNumber": "Nummer:", + "LabelDiscNumber": "Disk-nummer", + "LabelParentNumber": "For\u00e6ldre-nummer:", + "SortName": "Sorteringsnavn", + "ReleaseDate": "Udgivelsesdato", + "Continuing": "Fors\u00e6ttes", + "Ended": "F\u00e6rdig", + "HeaderEnabledFields": "Aktiv\u00e9r Felter", + "HeaderEnabledFieldsHelp": "Fjern fluebenet fra et felt for at l\u00e5se det og forhindre dets data fra at blive \u00e6ndret.", + "Backdrops": "Backdrops", + "Images": "Billeder", + "Runtime": "Afspilningstid", + "ProductionLocations": "Produktionslokationer", + "BirthLocation": "F\u00f8dselslokation", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Navn", + "Overview": "Overblik", + "LabelType": "Type:", + "LabelPersonRole": "Rolle:", + "LabelPersonRoleHelp": "Eksempel: Isbilschauff\u00f8r", + "Actor": "Skuespiller", + "Composer": "Komponist", + "Director": "Instrukt\u00f8r", + "GuestStar": "G\u00e6steskuespiller", + "Producer": "Producent", + "Writer": "Forfatter", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installerer {0}", + "PackageInstallCompleted": "{0} installation udf\u00f8rt.", + "PackageInstallFailed": "{0} installationen mislykkedes.", + "PackageInstallCancelled": "{0} installation afbrudt.", + "SeriesYearToPresent": "{0} - Nuv\u00e6rende", + "ValueOneItem": "1 emne", + "ValueOneSong": "1 sang", + "ValueSongCount": "{0} sange", + "ValueOneMovie": "1 film", + "ValueMovieCount": "{0} film", + "ValueOneSeries": "1 serie", + "ValueSeriesCount": "{0} serier", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episoder", + "ValueOneGame": "1 spil", + "ValueGameCount": "{0} spil", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} album", + "ValueOneMusicVideo": "1 musikvideo", + "ValueMusicVideoCount": "{0} musikvideoer", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Indtast et eller flere s\u00f8gekriterier.Fjern kriterier for at f\u00e5 flere s\u00f8geresultater.", + "PleaseEnterNameOrId": "Indtast venligst et navn eller eksternt Id.", + "MessageItemSaved": "Element gemt.", + "SearchResults": "S\u00f8geresultater", + "ServerNameIsRestarting": "Emby Server - {0} genstarter.", + "ServerNameIsShuttingDown": "Emby Server - {0} lukker ned.", + "HeaderDeleteItems": "Slet emner", + "ConfirmDeleteItems": "Sletning af disse emner vil b\u00e5de fjerne dem fra filsystemet og dit mediebibliotek. Er du sikker p\u00e5 at du vil forts\u00e6tte?", + "PleaseRestartServerName": "Genstart venligst Emby Server - {0}.", + "LabelSyncJobName": "Navn til synkroniserings job:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Kvalitet:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "L\u00e6r mere", + "LabelProfile": "Profil:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Maks. filer:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Sk\u00e6rmbilleder", + "MoveRight": "Flyt mod h\u00f8jre", + "MoveLeft": "Flyt mod venstre", + "ConfirmDeleteImage": "Slet billede?", + "HeaderEditImages": "Rediger billeder", + "Settings": "Indstillinger", + "ShowIndicatorsFor": "Vis indikatorer for:", + "NewEpisodes": "Nye episoder", + "Episodes": "Episodes", + "HDPrograms": "HD-programmer", + "Programs": "Programs", + "LiveBroadcasts": "Live-udsending", + "Premieres": "Premiere", + "RepeatEpisodes": "Gentag episoder", + "DvrSubscriptionRequired": "Emby DVR p\u00e5kr\u00e6ver et aktivt Emby Premiere abonnement.", + "HeaderCancelRecording": "Annuller Optagelse", + "CancelRecording": "Annuller optagelse", + "HeaderKeepRecording": "Bevar Optagelse", + "HeaderCancelSeries": "Annuller Serie", + "HeaderKeepSeries": "Bevar Serie", + "HeaderLearnMore": "L\u00e6r Mere", + "DeleteMedia": "Slet medie", + "SeriesSettings": "Serieindstillinger", + "HeaderRecordingOptions": "Optagelsesindstillinger", + "CancelSeries": "Annuller serie", + "DoNotRecord": "Optag ikke", + "HeaderSeriesOptions": "Serieindstillinger", + "LabelChannels": "Kanaler:", + "ChannelNameOnly": "Udelukkende kanal {0}", + "Anytime": "Altid", + "AnyLanguage": "Any language", + "AroundTime": "Omkring {0}", + "All": "All", + "AllChannels": "Alle kanaler", + "LabelRecord": "Optag:", + "NewEpisodesOnly": "Kun nye episoder", + "AllEpisodes": "Alle episoder", + "LabelStartWhenPossible": "Start n\u00e5r muligt:", + "LabelStopWhenPossible": "Stop n\u00e5r muligt:", + "MinutesBefore": "minutter f\u00f8r", + "MinutesAfter": "minutter efter", + "SkipEpisodesAlreadyInMyLibrary": "Optag ikke episoder som allerede findes i mit bibliotek", + "SkipEpisodesAlreadyInMyLibraryHelp": "Episoder bliver sammenlignet p\u00e5 s\u00e6son og episodenummer, n\u00e5r muligt.", + "LabelKeepUpTo": "Bevar op til:", + "AsManyAsPossible": "S\u00e5 mange som muligt", + "DefaultErrorMessage": "Det opstod en fejl ved behandlingen af foresp\u00f8rgslen. Pr\u00f8v igen senere.", + "LabelKeep:": "Bevar:", + "UntilIDelete": "Til jeg sletter", + "UntilSpaceNeeded": "Til pladsen er n\u00f8dvendig", + "Categories": "Kategorier", + "Sports": "Sport", + "News": "Nyheder", + "Movies": "Film", + "Kids": "B\u00f8rn", + "EnableColorCodedBackgrounds": "Aktiver farvekodet baggrunde", + "SortChannelsBy": "Sort\u00e9r kanaler efter:", + "RecentlyWatched": "Nyligt sete", + "ChannelNumber": "Kanalnummer", + "HeaderBenefitsEmbyPremiere": "Fordele ved Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "Nyd venligst et minuts afspilning. Tak fordi du pr\u00f8ver Emby.", + "HeaderTryPlayback": "Pr\u00f8v Afspilning", + "HowDidYouPay": "Hvordan betalte du?", + "IHaveEmbyPremiere": "Jeg har Emby Premiere", + "IPurchasedThisApp": "Jeg k\u00f8bte denne app", + "ButtonRestorePreviousPurchase": "Genskab Indk\u00f8b", + "ButtonUnlockWithPurchase": "L\u00e5s op for med K\u00f8b", + "ButtonUnlockPrice": "L\u00e5s op for {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere M\u00e5nedlig {0}", + "HeaderAlreadyPaid": "Allerede Betalt?", + "ButtonPlayOneMinute": "Afspil \u00c9t Minut", + "PlaceFavoriteChannelsAtBeginning": "Placer favoritkanaler i begyndelsen", + "HeaderUnlockFeature": "L\u00e5s op for Feature", + "MessageDidYouKnowCinemaMode": "Vidste du, at med Emby Premiere kan du opleve features s\u00e5 som Biograftilstand?", + "MessageDidYouKnowCinemaMode2": "Biograftilstand giver dig den \u00e6gte biografoplevelse med trailere og brugertilpassede introer f\u00f8r selve filmen.", + "HeaderPlayMyMedia": "Afspil mit Medie", + "HeaderDiscoverEmbyPremiere": "Oplev Emby Premiere", + "Items": "emner", + "OneChannel": "En kanal", + "ConfirmRemoveDownload": "Fjern download?", + "RemoveDownload": "Fjern download", + "KeepDownload": "Keep download", + "AddedOnValue": "Tilf\u00f8jet {0}", + "RemovingFromDevice": "Fjerner fra enhed", + "KeepOnDevice": "Bevar p\u00e5 enhed", + "CancelDownload": "Annuller download", + "SyncJobItemStatusReadyToTransfer": "Klar til at Overf\u00f8re", + "SyncJobItemStatusSyncedMarkForRemoval": "Fjerner fra enhed", + "SyncJobItemStatusQueued": "Sat i k\u00f8", + "SyncJobItemStatusConverting": "Konverterer", + "SyncJobItemStatusTransferring": "Overf\u00f8rer", + "SyncJobItemStatusSynced": "Downloadet", + "SyncJobItemStatusFailed": "Fejlet", + "SyncJobItemStatusRemovedFromDevice": "Fjern fra enhed", + "SyncJobItemStatusCancelled": "Annulleret", + "Retry": "Pr\u00f8v igen", + "HeaderMyDevice": "Min Enhed", + "Continue": "Forts\u00e6t", + "ContinueInSecondsValue": "Forts\u00e6t om {0} sekunder.", + "HeaderRemoteControl": "Fjernbetjening", + "Disconnect": "Afbryd", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Kvalitet", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Billedformat", + "Original": "Standard", + "Fill": "Udfyld", + "BestFit": "Bedste tilpasning", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Godkend", + "Reject": "Afvis", + "Connect": "Forbind", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Synkroniser til:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Fejl i afspilning", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Aktiver biograftilstand", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/de.json b/src/bower_components/emby-webcomponents/strings/de.json index 74577ea047..f9b06d34e9 100644 --- a/src/bower_components/emby-webcomponents/strings/de.json +++ b/src/bower_components/emby-webcomponents/strings/de.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolut", - "Accept": "Akzeptieren", - "AccessRestrictedTryAgainLater": "Der Zugriff ist derzeit eingeschränkt. Bitte versuche es später erneut.", - "Actor": "Schauspieler", - "Add": "Hinzufügen", - "AddToCollection": "Zur Sammlung hinzufügen", - "AddToPlayQueue": "Zur Abspielwarteschlange hinzufügen", - "AddToPlaylist": "Hinzufügen zur Wiedergabeliste", - "AddedOnValue": "Hinzugefügt {0}", - "Advanced": "Erweitert", - "AirDate": "Ausstrahlungsdatum", - "Aired": "Ausgestrahlt", - "Albums": "Alben", - "All": "Alle", - "AllChannels": "Alle Kanäle:", - "AllComplexFormats": "Alle komplexen Formate (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Alle Episoden", - "AllLanguages": "Alle Sprachen", - "AllowSeasonalThemes": "Erlaube automatische Saison-Themes", - "AllowSeasonalThemesHelp": "Wenn aktiviert, werden Saison-Themes von Zeit zu Zeit deine Theme-Einstellungen überschreiben.", - "AlwaysPlaySubtitles": "Untertitel immer anzeigen", - "AlwaysPlaySubtitlesHelp": "Untertitel die den Spracheinstellungen entsprechen werden unabhängig von der Tonspursprache geladen.", - "AnamorphicVideoNotSupported": "Anamorphes Video nicht unterstützt", - "AndroidUnlockRestoreHelp": "Um ihren voherigen Kauf wiederherzustellen, versichern Sie sich bitte, dass Sie auf dem Gerät mit dem selben Google (oder Amazon) Account angemeldet sind, mit dem Sie die Kauf ursprünglich getätigt haben. Stellen Sie sicher, dass der Appstore aktiviert und nicht durch eine Kindersicherung eingeschränkt ist und vergewissern Sie sich, dass sie über eine aktive Internetverbindung verfügen. Sie müssen dies nur einmal tun, um ihren vorherigen Kauf wiederherzustellen.", - "AnyLanguage": "Jede Sprache", - "Anytime": "Jederzeit", - "AroundTime": "Um {0}", - "Art": "Art", - "Artists": "Interpreten", - "AsManyAsPossible": "So viele wie möglich", - "Ascending": "Aufsteigend", - "AspectRatio": "Seitenverhältnis", - "AttemptingWakeServer": "Versuche Server aufwecken. Bitte warten...", - "AttributeNew": "Neu", - "AudioBitDepthNotSupported": "Audiobittiefe nicht unterstützt", - "AudioBitrateNotSupported": "Audio Bitrate nicht unterstützt", - "AudioChannelsNotSupported": "Audio Kanäle nicht unterstützt", - "AudioCodecNotSupported": "Audio Codec nicht unterstützt", - "AudioProfileNotSupported": "Audio Profil nicht unterstützt", - "AudioSampleRateNotSupported": "Audio Sample Rate nicht unterstützt", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Automatisch (basierend auf Spracheinstellung)", - "AutomaticallyConvertNewContent": "Konvertiere neue Inhalte automatisch", - "AutomaticallyConvertNewContentHelp": "Neue Inhalte in diesem Ordner werden automatisch konveriert.", - "AutomaticallySyncNewContent": "Lade neue Inhalte automatisch herunter", - "AutomaticallySyncNewContentHelp": "Neu zu diesem Ordner hinzugefügte Inhalte werden automatisch auf das Gerät heruntergeladen.", - "Backdrop": "Hintergrund", - "Backdrops": "Hintergründe", - "Banner": "Banner", - "BestFit": "Beste Übereinstimmung", - "BirthLocation": "Geburtsort", - "Books": "Bücher", - "Box": "Box", - "BoxRear": "Box (Rückseite)", - "Browse": "Blättern", - "BurnSubtitlesHelp": "Legt fest, ob der Server die Untertitel basierend auf deren Format einbrennen soll während der Videokonvertierung. Die Vermeidung des Einbrennen von Untertiteln verbessert die Serverperformance. Wähle Auto, um Bildfomate (z.B. VOBSUB, PGS, SUB/IDX, etc.) sowie bestimmte ASS/SSA-Untertitel einbrennen zu lassen.", - "ButtonCancel": "Abbrechen", - "ButtonGotIt": "Verstanden", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Eine Minute wiedergeben", - "ButtonRestart": "Neustart", - "ButtonRestorePreviousPurchase": "Kauf wiederherstellen", - "ButtonTryAgain": "Erneut versuchen", - "ButtonUnlockPrice": "{0} freischalten", - "ButtonUnlockWithPurchase": "Freischalten durch Kauf", - "CancelDownload": "Download abbrechen", - "CancelRecording": "Aufnahme abbrechen", - "CancelSeries": "Serien abbrechen", - "Categories": "Kategorien", - "ChannelNameOnly": "Nur Kanal {0}", - "ChannelNumber": "Kanalnummer", - "CinemaModeConfigurationHelp": "Der Kinomodus bringt das Kinoerlebnis direkt in dein Wohnzimmer, mit der Fähigkeit Trailer und benutzerdefinierte Intros vor dem Hauptfilm abzuspielen.", - "CinemaModeFeatureDescription": "Der Cinema Mode bringt das richtige Kinogefühl mit Trailern und eigenen Intros vor dem Hauptfilm.", - "CloudSyncFeatureDescription": "Synchronisiere deine Medien in die Cloud für ein Backup, eine Archivierung und Konvertierung.", - "Collections": "Sammlungen", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Farbraum", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community Bewertung", - "Composer": "Komponist", - "ConfigureDateAdded": "Bestimme in den Bibliotheks-Einstellungen des Jellyfin Server Dashboards, wie das Feld \"Hinzugefügt am\" interpretiert werden soll.", - "ConfirmDeleteImage": "Bild löschen?", - "ConfirmDeleteItem": "Löschen dieses Eintrages bedeutet das Löschen der Datei und das Entfernen aus der Medien-Bibliothek. Möchtest du wirklich fortfahren?", - "ConfirmDeleteItems": "Das Löschen dieser Objekte löscht die Dateien vom Laufwerk und in deiner Medienbibliothek. Bist du wirklich sicher?", - "ConfirmDeletion": "Bestätige Löschung", - "ConfirmEndPlayerSession": "Möchtest du Jellyfin auf {0} beenden?", - "ConfirmRemoveDownload": "Download entfernen?", - "Connect": "Verbinde", - "ContainerBitrateExceedsLimit": "Medienbitrate überschreitet das Limit.", - "ContainerNotSupported": "Container nicht unterstützt", - "Continue": "Fortfahren", - "ContinueInSecondsValue": "Fortfahren in {0} Sekunden.", - "ContinueWatching": "Weiterschauen", - "Continuing": "Fortlaufend", - "Convert": "Konvertieren", - "ConvertItemLimitHelp": "Optional. Lege die maximale Anzahl der zu konvertierenden Dateien fest.", - "ConvertUnwatchedVideosOnly": "Konvertiere nur ungesehen Videos", - "ConvertUnwatchedVideosOnlyHelp": "Nur ungesehene Videos werden konvertiert.", - "ConvertingDots": "Konvertieren...", - "Countries": "Länder", - "CriticRating": "Kritiker Bewertung", - "DateAdded": "Hinzugefügt am", - "DatePlayed": "Gesehen am", - "Days": "Tage", - "Default": "Standard", - "DefaultErrorMessage": "Es gab einen Fehler beim verarbeiten der Anfrage. Bitte versuche es später erneut.", - "DefaultSubtitlesHelp": "Untertitel werden gemäß der Standard- und Erzwungen-Ansicht aus den eingebetteten Metadaten geladen. Spracheinstellungen werden zur Verfügung gestellt, wenn mehrere Sprachen verfügbar sind.", - "Delete": "Löschen", - "DeleteMedia": "Medien löschen", - "Depressed": "Gedrückt", - "Descending": "Absteigend", - "Desktop": "Desktop", - "DirectPlayError": "Fehler bei der direkten Wiedergabe", - "DirectPlaying": "Direktes Abspielen", - "DirectStreamHelp1": "Das Medium ist mit dem Abspielgerät kompatibel bzgl. Auflösung und Codecs (H.264, AC3, etc.), besitzt jedoch einen inkompatiblen Dateicontainer (.mkv, .avi, .wmv, etc.). Das Video wird in Echtzeit neugepackt bevor es zum Abspielgerät gestreamt wird.", - "DirectStreamHelp2": "Direktes Streaming von Dateien benötigt sehr wenig Rechenleistung ohne Verlust der Videoqualität.", - "DirectStreaming": "Direktes Streaming", - "Director": "Regisseur", - "DirectorValue": "Regisseur: {0}", - "DirectorsValue": "Regisseure: {0}", - "Disc": "Disk", - "Disconnect": "Verbindung trennen", - "Dislike": "Mag ich nicht", - "Display": "Anzeige", - "DisplayInMyMedia": "Zeige auf Homescreen", - "DisplayInOtherHomeScreenSections": "Zeige auf dem Homescreen Bereiche wie 'Neueste Medien' oder 'Weiterschauen'", - "DisplayMissingEpisodesWithinSeasons": "Zeige fehlende Episoden innerhalb von Staffeln", - "DisplayMissingEpisodesWithinSeasonsHelp": "Dies sollte auch für Serienbibliotheken in den Jellyfin Server Einstellungen aktiviert sein.", - "DisplayModeHelp": "Bitte wähle den Typ des Bildschirms auf dem Du Jellyfin verwendest.", - "DoNotRecord": "Nicht aufnehmen", - "Down": "Runter", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Lege die maximale Anzahl der herunterzuladenden Dateien fest.", - "Downloaded": "Heruntergeladen", - "Downloading": "Lädt herunter", - "DownloadingDots": "Lädt herunter...", - "Downloads": "Downloads", - "DownloadsValue": "{0} Downloads", - "DropShadow": "Schlagschatten", - "DvrFeatureDescription": "Plane individuelle Aufnahmen von Live-TV, Serien und mehr mit Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR benötigt eine aktive Jellyfin Premiere Mitgliedschaft.", - "Edit": "Bearbeiten", - "EditImages": "Bearbeite Bilder", - "EditMetadata": "Bearbeite Metadaten", - "EditSubtitles": "Untertitel bearbeiten", - "EnableBackdrops": "Aktiviere Hintergründe", - "EnableBackdropsHelp": "Wenn aktiviert, werden während des Browsens durch die Bibliothek auf einigen Seiten passende Hintergründe angezeigt.", - "EnableCinemaMode": "Aktiviere den Kino-Modus", - "EnableColorCodedBackgrounds": "Aktiviere farbige Hintergründe", - "EnableDisplayMirroring": "Aktiviere Display-Weiterleitung", - "EnableExternalVideoPlayers": "Aktiviere externe Videoplayer", - "EnableExternalVideoPlayersHelp": "Ein Menü für externe Videoplayer wird beim Start der Videowiedergabe angezeigt.", - "EnableNextVideoInfoOverlay": "Aktiviere \"Next-Video-Info\" während der Wiedergabe", - "EnableNextVideoInfoOverlayHelp": "Zeige Informationen über das nächste abzuspielende Video in der aktuellen Abspielliste am Ende des laufenden Videos an.", - "EnableThemeSongs": "Aktiviere Titelmelodien", - "EnableThemeSongsHelp": "Wenn aktiviert, wird Titelmusik während des Browsens durch die Bibliothek im Hintergrund abgespielt.", - "EnableThemeVideos": "Altiviere Titelvideos", - "EnableThemeVideosHelp": "Wenn aktiviert, wird ein Titelvideo während dem Durchsuchen durch die Bibliothek im Hintergrund abgespielt.", - "Ended": "Beendent", - "EndsAtValue": "Endet um {0}", - "Episodes": "Episoden", - "Error": "Fehler", - "ErrorAddingGuestAccount1": "Ein Fehler trat beim Hinzufügen des Jellyfin Connect Kontos auf. Hat Ihr Gast ein Jellyfin Konto erstellt? Sie können sich hier anmelden {0}.", - "ErrorAddingGuestAccount2": "Wenn du immer noch ein Problem hast, sende bitte eine E-Mail an {0} mit deiner E-Mail-Adresse und die der anderen als Inhalt.", - "ErrorAddingJellyfinConnectAccount1": "Ein Fehler trat beim hinzufügen des Jellyfin-Connect Kontos auf. Hast du bereits ein Jellyfin Konto? Melde dich hier an: {0}.", - "ErrorAddingJellyfinConnectAccount2": "Wenn du immer noch ein Problem hast, sende bitte eine E-Mail an {0} von der E-Mail-Adresse die du mit dem Jellyfin-Account nutzt.", - "ErrorConnectServerUnreachable": "Es gab einen Fehler bei bei der Ausführung des Funktion. Dein Server ist nicht in der Lage unsere Jellyfin-Connect-Server zu erreichen um {0}. Stelle bitte sicher, dass dein Server eine aktive Internetverbindung hat und die Kommunikations durch die Firewall oder andere installierte Sicherheitssoftware erlaubt wurde.", - "ErrorDeletingItem": "Fehler beim Löschen des Mediums vom Jellyfin Server. Bitte stelle sicher dass der Jellyfin Server Schreibzugriff auf den Dateiordner hat und versuche es erneut.", - "ErrorReachingJellyfinConnect": "Fehler bei der Verbindung zum Jellyfin Connect Server. Stelle bitte sicher, dass du über eine aktive Internetverbindung verfügst und versuche es erneut.", - "ErrorRemovingJellyfinConnectAccount": "Fehler beim Entfernen des Jellyfin Connect Kontos. Bitte stelle sicher, dass du über eine aktive Internetverbindung verfügst und versuche es erneut.", - "ExtraLarge": "Extragroß", - "Extras": "Extras", - "Favorite": "Favorit", - "Favorites": "Favoriten", - "FeatureRequiresJellyfinPremiere": "Dieses Feature benötigt eine aktive Jellyfin Premiere Mitgliedschaft.", - "Features": "Features", - "File": "Datei", - "Fill": "Ausfüllen", - "Filters": "Filter", - "Folders": "Verzeichnisse", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Genieße Zugriff auf kostenlose Jellyfin Apps für deine Geräte.", - "Friday": "Freitag", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Nach Serien gruppieren", - "GroupVersions": "Gruppiere Versionen", - "GuestStar": "Gaststar", - "GuestUserNotFound": "Benutzer nicht gefunden. Bitte stelle die korrekte Schreibweise sicher und versuche es erneut. Du kannst auch die Emailadresse verwenden.", - "Guide": "TV Guide", - "HDPrograms": "HD Programme", - "HeaderActiveRecordings": "Aktive Aufnahmen", - "HeaderAddToCollection": "Zu Sammlung hinzufügen", - "HeaderAddToPlaylist": "Zur Wiedergabeliste hinzufügen", - "HeaderAddUpdateImage": "Bild hinzufügen/aktualisieren", - "HeaderAlbumArtists": "Albuminterpreten", - "HeaderAlreadyPaid": "Schon bezahlt?", - "HeaderAppearsOn": "Erscheint auf", - "HeaderAudioBooks": "Hörbücher", - "HeaderAudioSettings": "Audioeinstellungen", - "HeaderBecomeProjectSupporter": "Hol dir Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Vorteile von Jellyfin Premiere", - "HeaderCancelRecording": "Aufnahme abbrechen", - "HeaderCancelSeries": "Serie abbrechen", - "HeaderCinemaMode": "Kinomodus", - "HeaderCloudSync": "Cloud Synchronisation", - "HeaderConfirmRecordingCancellation": "Bestätige Aufzeichnungsabbruch", - "HeaderContinueListening": "Weiterhören", - "HeaderContinueWatching": "Weiterschauen", - "HeaderConvertYourRecordings": "Konvertiere deine Aufnahmen", - "HeaderCustomizeHomeScreen": "Startbildschirm konfigurieren", - "HeaderDeleteItem": "Lösche Element", - "HeaderDeleteItems": "Lösche Objekte", - "HeaderDisplaySettings": "Anzeige Einstellungen", - "HeaderDownloadSettings": "Downloadeinstellungen", - "HeaderEditImages": "Bilder bearbeiten", - "HeaderEnabledFields": "Aktiviere Felder", - "HeaderEnabledFieldsHelp": "Wähle Felder ab um das Ändern von Daten zu verhindern.", - "HeaderExternalIds": "Externe IDs:", - "HeaderFavoriteAlbums": "Lieblingsalben", - "HeaderFavoriteArtists": "Lieblingskünstler", - "HeaderFavoriteCollections": "Lieblingssammlungen", - "HeaderFavoriteEpisodes": "Lieblingsepisoden", - "HeaderFavoriteGames": "Lieblingsspiele", - "HeaderFavoriteMovies": "Lieblingsfilme", - "HeaderFavoritePlaylists": "Lieblingswiedergabelisten", - "HeaderFavoriteShows": "Lieblingsserien", - "HeaderFavoriteSongs": "Lieblingssongs", - "HeaderFavoriteVideos": "Lieblingsvideos", - "HeaderFreeApps": "Kostenlose Jellyfin Apps", - "HeaderHomeScreen": "Startseite", - "HeaderIdentifyItemHelp": "Gib ein oder mehrere Suchkriterien ein. Entferne Kriterien um die Suchergebnisse zu erweitern.", - "HeaderInvitationSent": "Einladung verschickt", - "HeaderJellyfinAccountAdded": "Jellyfin Konto hinzugefügt", - "HeaderJellyfinAccountRemoved": "Jellyfin Konto entfernt", - "HeaderKeepRecording": "Aufnahme behalten", - "HeaderKeepSeries": "Serie behalten", - "HeaderLatestChannelItems": "Neueste Channelinhalte", - "HeaderLatestChannelMedia": "Neueste Channelinhalte", - "HeaderLatestFrom": "Neuestes von {0}", - "HeaderLatestMedia": "Neueste Medien", - "HeaderLatestRecordings": "Neueste Aufnahmen", - "HeaderLearnMore": "Erfahre mehr", - "HeaderLibraryFolders": "Bibliotheksverzeichnisse", - "HeaderLibraryOrder": "Bibliotheksreihenfolge", - "HeaderMetadataSettings": "Metadaten Einstellungen", - "HeaderMusicQuality": "Musikqualität", - "HeaderMyDevice": "Mein Gerät", - "HeaderMyDownloads": "Meine Downloads", - "HeaderMyMedia": "Meine Medien", - "HeaderMyMediaSmall": "Meine Medien (Klein)", - "HeaderNewRecording": "Neue Aufnahme", - "HeaderNextEpisodePlayingInValue": "Nächste Episode wird abgespielt in {0}", - "HeaderNextUp": "Als Nächstes", - "HeaderNextVideoPlayingInValue": "Nächstes Video wird abgespielt in {0}", - "HeaderOfflineDownloads": "Offline Medien", - "HeaderOfflineDownloadsDescription": "Lade Medien auf deine Geräte herunter um sie einfach offline zu nutzen.", - "HeaderOnNow": "Gerade läuft", - "HeaderPhotoAlbums": "Fotoalben", - "HeaderPlayMyMedia": "Spiele meine Medien ab", - "HeaderPlayOn": "Abspielen auf", - "HeaderPlaybackError": "Wiedergabefehler", - "HeaderRecordingOptions": "Aufnahmeeinstellungen", - "HeaderRemoteControl": "Fernsteuerung", - "HeaderRestartingJellyfinServer": "Jellyfin Server neu starten", - "HeaderSaySomethingLike": "Sage etwas wie...", - "HeaderSecondsValue": "{0} Sekunden", - "HeaderSelectDate": "Datum wählen", - "HeaderSeriesOptions": "Serienoptionen", - "HeaderSeriesStatus": "Serienstatus:", - "HeaderSpecialEpisodeInfo": "Spezialepisoden Information", - "HeaderStartNow": "Starte jetzt", - "HeaderStopRecording": "Aufnahme stoppen", - "HeaderSubtitleAppearance": "Untertiteldarstellung", - "HeaderSubtitleSettings": "Untertiteleinstellungen", - "HeaderSyncRequiresSub": "Downloads benötigen ein aktives Jellyfin Premiere Abonnement.", - "HeaderTermsOfPurchase": "Bestellungsbedingungen", - "HeaderTryPlayback": "Wiedergabe ausprobieren", - "HeaderUnlockFeature": "Feature freischalten", - "HeaderUploadImage": "Bild hochladen", - "HeaderVideoQuality": "Videoqualität", - "HeaderVideoType": "Videotyp:", - "HeaderWaitingForWifi": "Warte auf WLAN", - "HeaderWakeServer": "Server aufwecken", - "HeaderYouSaid": "Du sagtest...", - "Help": "Hilfe", - "Hide": "Verstecke", - "HideWatchedContentFromLatestMedia": "Verberge gesehene Inhalte von neuesten Medien.", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "Wie hast Du bezahlt?", - "IHaveJellyfinPremiere": "Ich besitze Jellyfin Premiere", - "IPurchasedThisApp": "Ich habe diese App gekauft", - "Identify": "Identifizieren", - "Images": "Bilder", - "ImdbRating": "IMDb Bewertung", - "InstallingPackage": "Installiere {0}", - "InstantMix": "Schnellmix", - "InterlacedVideoNotSupported": "Interlaced Video nicht unterstützt", - "ItemCount": "{0} Einträge", - "Items": "Einträge", - "KeepDownload": "Download behalten", - "KeepOnDevice": "Auf Gerät behalten", - "Kids": "Kinder", - "Label3DFormat": "3D Format:", - "LabelAirDays": "Ausstrahlungstage:", - "LabelAirTime": "Ausstrahlungszeit:", - "LabelAirsAfterSeason": "Ausstrahlungen nach Staffel:", - "LabelAirsBeforeEpisode": "Ausstrahlungen vor Episode:", - "LabelAirsBeforeSeason": "Ausstrahlungen vor Staffel:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Alben Interpreten:", - "LabelArtists": "Interpreten:", - "LabelArtistsHelp": "Trenne mehrere Einträge durch ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Bevorzugte Audiosprache:", - "LabelBirthDate": "Geburtsdatum:", - "LabelBirthYear": "Geburtsjahr:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Untertitel einbrennen:", - "LabelChannels": "Kanäle:", - "LabelCollection": "Sammlung:", - "LabelCommunityRating": "Community Bewertung:", - "LabelContentType": "Typ des Inhalts:", - "LabelConvertTo": "Konvertiere nach:", - "LabelCountry": "Land:", - "LabelCriticRating": "Kritiker Bewertung:", - "LabelCustomRating": "Eigene Bewertung:", - "LabelDashboardTheme": "Server Dashboard Theme:", - "LabelDateAdded": "Hinzugefügt am:", - "LabelDateTimeLocale": "Datum/Zeit lokal:", - "LabelDeathDate": "Todesdatum:", - "LabelDefaultScreen": "Standardscreen:", - "LabelDiscNumber": "Discnummer:", - "LabelDisplayLanguage": "Anzeigesprache:", - "LabelDisplayLanguageHelp": "Die Übersetzung von Jellyfin ist ein laufendes Projekt.", - "LabelDisplayMode": "Bildschirmmodus:", - "LabelDisplayOrder": "Anzeigereihenfolge:", - "LabelDropImageHere": "Fotos hierher ziehen oder klicken im zu browsen.", - "LabelDropShadow": "Schlagschatten:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-Mail Adresse:", - "LabelEndDate": "Endzeit:", - "LabelEpisodeNumber": "Episodennummer:", - "LabelFont": "Schriftart:", - "LabelHomeNetworkQuality": "Heimnetzwerkqualität:", - "LabelHomeScreenSectionValue": "Startseitenbereich {0}:", - "LabelImageType": "Bildtyp:", - "LabelInternetQuality": "Internetqualität:", - "LabelItemLimit": "Maximale Anzahl:", - "LabelKeep:": "Behalten:", - "LabelKeepUpTo": "Fortführen:", - "LabelLanguage": "Sprache:", - "LabelLockItemToPreventChanges": "Sperre diesen Eintrag um zukünftige Änderungen zu verhindern", - "LabelMaxChromecastBitrate": "Max Chromcast Datenrate:", - "LabelMetadataDownloadLanguage": "Bevorzugte Sprache für Downloads:", - "LabelName": "Name:", - "LabelNumber": "Nummer:", - "LabelOriginalAspectRatio": "Original Seitenverhältnis:", - "LabelOriginalTitle": "Original Titel:", - "LabelOverview": "Übersicht:", - "LabelParentNumber": "Ursprungsnummer:", - "LabelParentalRating": "Altersfreigabe:", - "LabelPath": "Pfad:", - "LabelPersonRole": "Rolle:", - "LabelPersonRoleHelp": "Beispiel: Eiswagenfahrer", - "LabelPlaceOfBirth": "Geburtsort:", - "LabelPlayDefaultAudioTrack": "Spiele unabhängig von der Sprache die Standardtonspur", - "LabelPlaylist": "Wiedergabeliste", - "LabelPreferredSubtitleLanguage": "Bevorzugte Untertitelsprache:", - "LabelProfile": "Profil:", - "LabelQuality": "Qualität:", - "LabelReasonForTranscoding": "Grund für die Transkodierung:", - "LabelRecord": "Aufnahme:", - "LabelRefreshMode": "Aktualisierungsmodus:", - "LabelReleaseDate": "Veröffentlichungsdatum:", - "LabelRuntimeMinutes": "Laufzeit (Minuten):", - "LabelScreensaver": "Bildschirmschoner:", - "LabelSeasonNumber": "Staffelnummer:", - "LabelSelectFolderGroups": "Gruppiere Inhalte von folgenden Verzeichnissen automatisch zu Ansichten wie beispielsweise Filme, Musik und TV:", - "LabelSelectFolderGroupsHelp": "Verzeichnisse die nicht markiert sind werden alleine mit ihren eigenen Ansichten angezeigt.", - "LabelShortOverview": "Kurzübersicht:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Sprungweite rückwärts:", - "LabelSkipForwardLength": "Sprungweite vorwärts:", - "LabelSortBy": "Sortiert nach:", - "LabelSortOrder": "Sortierreihenfolge", - "LabelSortTitle": "Sortierungs Titel:", - "LabelSoundEffects": "Soundeffekte:", - "LabelSource": "Quelle:", - "LabelStartWhenPossible": "Starte wenn möglich:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stoppe wenn möglich", - "LabelSubtitlePlaybackMode": "Untertitelmodus:", - "LabelSubtitles": "Untertitel:", - "LabelSyncJobName": "Synchronisations-Aufgabe:", - "LabelSyncNoTargetsHelp": "Es sieht so aus als würdest du aktuell keine Apps verwenden, die Offline-Downloads unterstützen.", - "LabelSyncTo": "Synchronisiere mit:", - "LabelTVHomeScreen": "TV-Mode Startseite", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Hintergrundfarbe des Textes:", - "LabelTextColor": "Textfarbe:", - "LabelTextSize": "Textgröße", - "LabelTheme": "Theme:", - "LabelTitle": "Titel:", - "LabelTrackNumber": "Stück Nummer:", - "LabelType": "Typ:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Hintergrundfarbe des Textes:", - "LabelYear": "Jahr:", - "Large": "Groß", - "LatestFromLibrary": "Neueste {0}", - "LearnHowYouCanContribute": "Erfahre, wie du unterstützen kannst.", - "LearnMore": "Erfahre mehr", - "Like": "Mag ich", - "LinksValue": "Links: {0}", - "List": "Liste", - "Live": "Live", - "LiveBroadcasts": "Liveübertragungen", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Streame Live TV zu jeder Jellyfin App mit einem kompatiblen TV Tuner , der auf deinem Jellyfin Server installiert ist.", - "LiveTvRequiresUnlock": "Live TV benötigt eine aktive Jellyfin Premiere Mitgliedschaft.", - "Logo": "Logo", - "ManageRecording": "Aufnahme verwalten", - "MarkPlayed": "Markiere \"als gesehen\"", - "MarkUnplayed": "Markiere \"als ungesehen\"", - "MarkWatched": "Als gesehen markieren", - "MediaIsBeingConverted": "Das Medium wird in ein Format konvertiert, das mit dem Abspielgerät kompatibel ist.", - "Medium": "Mittel", - "Menu": "Menü", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Ein aktives Jellyfin Premium Abo wird bennötigt um automatische Serienaufnahmen zu erstellen.", - "MessageAreYouSureDeleteSubtitles": "Bist du dir sicher diese Untertitel Datei löschen zu wollen?", - "MessageConfirmRecordingCancellation": "Aufzeichnung abbrechen?", - "MessageDownloadQueued": "Download eingereiht.", - "MessageFileReadError": "Es gab einen Fehler beim Lesen der Datei. Bitte versuche es erneut.", - "MessageIfYouBlockedVoice": "Wenn du die Sprachsteuerung für die App nicht erlaubt hast, musst du dies vor einem erneuten Versuch ändern.", - "MessageInvitationSentToNewUser": "Eine Email wurde an {0} mit einer Einladung zur Anmeldung an Jellyfin gesendet.", - "MessageInvitationSentToUser": "Eine E-Mail mit der Einladung zum Sharing ist an {0} geschickt worden.", - "MessageItemSaved": "Element gespeichert", - "MessageItemsAdded": "Einträge hinzugefügt", - "MessageJellyfinAccontRemoved": "Das Jellyfin Konto wurde von diesem Benutzer entfernt.", - "MessageJellyfinAccountAdded": "Das Jellyfin Konto wurde diesem Benutzer hinzugefügt.", - "MessageLeaveEmptyToInherit": "Freilassen für die Vererbung von Berechtigungen oder dem systemweiten Standardwert.", - "MessageNoDownloadsFound": "Keine Offline-Downloads. Downloade deine Medien um sie offline abzuspielen indem du Download in der App anklickst.", - "MessageNoServersAvailableToConnect": "Es steht kein verbindungsbereiter Server zur Verfügung. Wenn du eingeladen wurdest, vergewissere dich, dass du die Einladung weiter unten akzeptierst oder den Link in der E-Mail angeklickt hast.", - "MessageNoSyncJobsFound": "Keine Downloads gefunden. Um Downloadaufträge zu erstellen verwende die Downloadbuttons in der App.", - "MessagePendingJellyfinAccountAdded": "Das Jellyfin Konto wurde diesem Benutzer hinzugefügt. Eine Emails wird an den Besitzer dieses Kontos gesendet. Die Einladung muss mit einem Klick auf den Link in der Email bestätigt werden.", - "MessagePlayAccessRestricted": "Das Abspielen dieses Inhaltes ist derzeit eingeschränkt. Bitte kontaktiere deinen Jellyfin Server-Administrator für weitere Informationen.", - "MessageToValidateSupporter": "Wenn du eine aktive Jellyfin Premiere Mitgliedschaft hast, stelle bitte sicher, dass du diese über das Jellyfin Server Dashboard eingerichtet hast (Hauptmenu -> Jellyfin Premiere).", - "MessageUnlockAppWithPurchaseOrSupporter": "Schalte diese Funktion mit einer kleinen einmaligen Gebühr oder einem aktiven Jellyfin Premium Abo frei.", - "MessageUnlockAppWithSupporter": "Schalte diese Funktion mit einem aktiven Jellyfin Premium Abo frei.", - "MessageWeDidntRecognizeCommand": "Entschuldigung, dieses Kommando konnten wir nicht erkennen.", - "MinutesAfter": "Minuten nach", - "MinutesBefore": "Minuten vor", - "Mobile": "Mobil / Tablet", - "Monday": "Montag", - "More": "Mehr", - "MoveLeft": "Nach links bewegen", - "MoveRight": "Nach rechts bewegen", - "Movies": "Filme", - "MySubtitles": "Meine Untertitel", - "Name": "Name", - "NewCollection": "Neue Collection", - "NewCollectionHelp": "Sammlungen ermöglichen personallisierte Gruppen von Filmen oder anderen Medien.", - "NewCollectionNameExample": "Beispiel: Star Wars Collection", - "NewEpisodes": "Neue Episoden", - "NewEpisodesOnly": "Nur neue Episoden", - "News": "Nachrichten", - "Next": "Nächstes", - "No": "Nein", - "NoItemsFound": "Keine Einträge gefunden.", - "NoSubtitleSearchResultsFound": "Keine Ergebnisse gefunden.", - "NoSubtitles": "Keine Untertitel", - "NoSubtitlesHelp": "Untertitel werden standardmäßig nicht geladen. Sie können aber während der Wiedergabe manuell aktiviert werden.", - "None": "Keines", - "Normal": "Normal", - "Off": "Aus", - "OneChannel": "Ein Kanal", - "OnlyForcedSubtitles": "Nur erzwungene Untertitel", - "OnlyForcedSubtitlesHelp": "Nur Untertitel, die als erzwungen markiert wurden, werden geladen.", - "OnlyImageFormats": "Nur Bildformate (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Öffnen", - "OptionNew": "Neu...", - "Original": "Original", - "OriginalAirDateValue": "Erstausstrahlung: {0}", - "Overview": "Übersicht", - "PackageInstallCancelled": "{0} Installation abgebrochen", - "PackageInstallCompleted": "{0} Installation abgeschlossen", - "PackageInstallFailed": "{0} Installation fehlgeschlagen", - "ParentalRating": "Altersfreigabe", - "People": "Personen", - "PerfectMatch": "Perfektes Ergbnis", - "Photos": "Fotos", - "PlaceFavoriteChannelsAtBeginning": "Platziere favorisierte Kanäle am Anfang", - "Play": "Abspielen", - "PlayAllFromHere": "Spiele alles von hier", - "PlayCount": "Wiedergabezähler", - "PlayFromBeginning": "Von Beginn abspielen", - "PlayNext": "Spiele als Nächstes ab", - "PlayNextEpisodeAutomatically": "Starte nächste Episode automatisch", - "PlaybackErrorNoCompatibleStream": "Derzeit sind keine kompatiblen Stream verfügbar. Bitte versuche es später nochmal oder kontaktiere deinen Systemadministrator für weitere Informationen.", - "PlaybackErrorNotAllowed": "Die verfügst derzeit über keine Berechtigung um diesen Inhalt abzuspielen. Bitte kontaktiere deinen Systemadministrator für weitere Informationen.", - "PlaybackErrorPlaceHolder": "Bitte lege die Disc ein um das Video abzuspielen.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "Um die Wiedergabeeinstellungen zu ändern, stoppen Sie die Wiedergabe und klicken Sie auf Ihr Benutzer-Icon in der oberen rechten Ecke der App.", - "Played": "Gesehen", - "Playlists": "Wiedergabelisten", - "PleaseEnterNameOrId": "Bitte gib einen Namen oder eine externe Id an.", - "PleaseRestartServerName": "Bitte starte Jellyfin Server - {0} neu.", - "PleaseSelectDeviceToSyncTo": "Bitte wähle ein Download-Zielgerät.", - "PleaseSelectTwoItems": "Bitte wähle mindestens zwei Optionen aus.", - "Premiere": "Premiere", - "Premieres": "Premieren", - "Previous": "Vorheriges", - "Primary": "Primär", - "PrivacyPolicy": "Datenschutzbestimmungen", - "Producer": "Produzent", - "ProductionLocations": "Drehorte", - "Programs": "Programme", - "PromoConvertRecordingsToStreamingFormat": "Konvertiere Aufnahmen automatisch in ein Streaming-freundliches Format mit Jellyfin Premiere. Aufnahmen werden, basierend auf den Jellyfin Server-Einstellungen, dynamisch zu MP4 oder MKV konvertiert.", - "Quality": "Qualität", - "QueueAllFromHere": "Setze alles von hier auf Warteschlange", - "Raised": "Angehoben", - "RecentlyWatched": "Kürzlich gesehen", - "Record": "Aufnehmen", - "RecordSeries": "Serie aufnehmen", - "RecordingCancelled": "Aufzeichnung abgebrochen.", - "RecordingScheduled": "Aufnahme geplant.", - "Recordings": "Aufnahmen", - "RefFramesNotSupported": "Anzahl der Videoreferenzframes nicht unterstützt", - "Refresh": "Aktualisieren", - "RefreshDialogHelp": "Metadaten werden auf Basis der Einstellungen und Internet Services in den Jellyfin Server Einstellungen aktualisiert.", - "RefreshMetadata": "Aktualisiere Metadaten", - "RefreshQueued": "Aktualisierung eingereiht.", - "Reject": "Ablehnen", - "ReleaseDate": "Veröffentlichungsdatum", - "RemoveDownload": "Download entfernen", - "RemoveFromCollection": "Aus Sammlung entfernen", - "RemoveFromPlaylist": "Von Wiedergabeliste entfernen", - "RemovingFromDevice": "Vom Gerät entfernen", - "Repeat": "Wiederholen", - "RepeatAll": "Alles wiederholen", - "RepeatEpisodes": "Wiederholung Episoden", - "RepeatMode": "Wiederholungsmodus", - "RepeatOne": "Dieses wiederholen", - "ReplaceAllMetadata": "Ersetze alle Metadaten", - "ReplaceExistingImages": "Ersetze vorhandene Bilder", - "RestartPleaseWaitMessage": "Warte bitte bis der Jellyfin Server heruntergefahren und neu gestartet wurde. Dieser Vorgang dauert 1 bis 2 Minuten.", - "ResumeAt": "Fortsetzen bei {0}", - "Retry": "Wiederholen", - "RunAtStartup": "Nach Hochfahren automatisch starten", - "Runtime": "Laufzeit", - "Saturday": "Samstag", - "Save": "Speichern", - "ScanForNewAndUpdatedFiles": "Scanne nach neuen und aktualisierten Dateien", - "Schedule": "Zeitplan", - "Screenshot": "Bildschirmfoto", - "Screenshots": "Screenshots", - "Search": "Suche", - "SearchForCollectionInternetMetadata": "Suche im Internet nach Bildmaterial und Metadaten", - "SearchForMissingMetadata": "Suche nach fehlenden Metadaten", - "SearchForSubtitles": "Suche nach Untertiteln", - "SearchResults": "Suchergebnisse", - "SecondaryAudioNotSupported": "Tonspurwechsel nicht unterstützt", - "SeriesCancelled": "Serie abgebrochen.", - "SeriesDisplayOrderHelp": "Sortiere Episoden nach Ausstrahlungsdatum, DVD Reihenfolge oder absoluter Nummerierung.", - "SeriesRecordingScheduled": "Serien-Aufnahme geplant.", - "SeriesSettings": "Serieneinstellungen", - "SeriesYearToPresent": "{0}-Heute", - "ServerNameIsRestarting": "Jellyfin Server - {0} startet neu.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} fährt herunter.", - "ServerUpdateNeeded": "Dieser Jellyfin Server muss aktualisiert werden. Um die neueste Version herunterzuladen, besuche bitte {0}", - "Settings": "Einstellungen", - "SettingsSaved": "Einstellungen gespeichert.", - "Share": "Teilen", - "ShowIndicatorsFor": "Zeige Indikatoren für:", - "ShowTitle": "Zeige Titel", - "ShowYear": "Zeige Jahr", - "Shows": "Serien", - "Shuffle": "Zufallswiedergabe", - "SkipEpisodesAlreadyInMyLibrary": "Nehme keine Episoden auf, die schon in meiner Bibliothek verfügbar sind.", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episoden werden mittels Staffel- und Episodennummer verglichen, wenn verfügbar.", - "Small": "Klein", - "SmallCaps": "Kapitälchen", - "Smaller": "Kleiner", - "Smart": "Smart", - "SmartSubtitlesHelp": "Untertitel, die den Spracheinstellungen entsprechen, werden nur bei einer Tonspur in fremder Sprache heruntergeladen.", - "Songs": "Songs", - "Sort": "Sortieren", - "SortByValue": "Sortieren nach {0}", - "SortChannelsBy": "Sortiere Kanäle nach:", - "SortName": "Sortiername", - "Sports": "Sport", - "StatsForNerds": "Statistiken für Tüftler", - "StopRecording": "Aufnahme stoppen", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Diese Einstellungen werden auch auf jede Chromecast-Wiedergabe angewendet, die von diesem Gerät gestartet wird.", - "SubtitleAppearanceSettingsDisclaimer": "Diese Einstellungen werden nicht auf grafische Untertitel (PGS, DVD, etc.) oder Untertitel mit eingebettetem Style-Elementen (ASS/SSA) angewendet.", - "SubtitleCodecNotSupported": "Untertitelformat nicht unterstützt", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "Um das Aussehen der Untertitel und die Spracheinstellungen zu ändern, stoppen Sie die Wiedergabe und klicken Sie auf Ihr Benutzer-Icon in der oberen rechten Ecke der App.", - "Subtitles": "Untertitel", - "Suggestions": "Empfehlungen", - "Sunday": "Sonntag", - "Sync": "Synchronisation", - "SyncJobItemStatusCancelled": "Abgebrochen", - "SyncJobItemStatusConverting": "Konvertiere", - "SyncJobItemStatusFailed": "Fehlgeschlagen", - "SyncJobItemStatusQueued": "In Warteschlange", - "SyncJobItemStatusReadyToTransfer": "Fertig zum Transfer", - "SyncJobItemStatusRemovedFromDevice": "Vom Gerät entfernt", - "SyncJobItemStatusSynced": "Heruntergeladen", - "SyncJobItemStatusSyncedMarkForRemoval": "Vom Gerät entfernen", - "SyncJobItemStatusTransferring": "Übertrage", - "SyncUnwatchedVideosOnly": "Lade nur ungesehene Videos herunter", - "SyncUnwatchedVideosOnlyHelp": "Nur ungesehene Video werden heruntergeladen. Videos werden entfernt sobald diese auf dem Gerät angeschaut wurden.", - "SyncingDots": "Synchronisieren...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Nutzungsbedingungen", - "ThankYouForTryingEnjoyOneMinute": "Genieße eine Minute Wiedergabe. Danke, dass du Jellyfin ausprobierst.", - "ThemeSongs": "Titelsongs", - "ThemeVideos": "Titelvideos", - "TheseSettingsAffectSubtitlesOnThisDevice": "Diese Einstellungen beeinflussen Untertitel auf diesem Gerät", - "Thumb": "Thumb", - "Thursday": "Donnerstag", - "TrackCount": "{0} Titel", - "Trailer": "Trailer", - "Trailers": "Trailer", - "Transcoding": "Transcoding", - "TryMultiSelect": "Versuche Mehrfachauswahl", - "TryMultiSelectMessage": "Für eine Mehrfachauswahl klicke und halte ein Poster. Wähle die Einträge die du bearbeiten möchten. Versuch es!", - "Tuesday": "Dienstag", - "Uniform": "Einheitlich", - "UnlockGuide": "Guide freischalten", - "Unplayed": "Ungesehen", - "Unrated": "Nicht bewertet", - "UntilIDelete": "Bis ich lösche", - "UntilSpaceNeeded": "Bis Speicherplatz benötigt wird", - "Up": "Hoch", - "Upload": "Hochladen", - "ValueAlbumCount": "{0} Alben", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} Episoden", - "ValueGameCount": "{0} Spiele", - "ValueMinutes": "{0} Minuten", - "ValueMovieCount": "{0} Filme", - "ValueMusicVideoCount": "{0} Musikvideos", - "ValueOneAlbum": "1 Album", - "ValueOneEpisode": "1 Episode", - "ValueOneGame": "1 Spiel", - "ValueOneItem": "1 Eintrag", - "ValueOneMovie": "1 Film", - "ValueOneMusicVideo": "1 Musikvideo", - "ValueOneSeries": "1 Serie", - "ValueOneSong": "1 Lied", - "ValueSeconds": "{0} Sekunden", - "ValueSeriesCount": "{0} Serien", - "ValueSongCount": "{0} Lieder", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertikal", - "VideoBitDepthNotSupported": "Videobittiefe nicht unterstützt", - "VideoCodecNotSupported": "Video Codec nicht unterstützt", - "VideoFramerateNotSupported": "Videoframerate nicht unterstützt", - "VideoLevelNotSupported": "Video Level nicht unterstützt", - "VideoProfileNotSupported": "Videoprofil nicht unterstützt", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video Auflösung nicht unterstützt", - "ViewAlbum": "Zeige Album", - "ViewArtist": "Zeige Darsteller", - "VoiceInput": "Spracheingabe", - "WakeServer": "Server aufwecken", - "WakeServerError": "Wake On LAN Pakete wurden an deinen Server geschickt, aber wir konnten deinen Jellyfin Server nicht erreichen. Deine Maschine braucht vielleicht etwas länger um aufzuwachen oder Jellyfin Server wird zur Zeit nicht ausgeführt.", - "WakeServerSuccess": "Erfolgreich!", - "Watched": "Gesehen", - "Wednesday": "Mittwoch", - "WifiRequiredToDownload": "Um den Download fortzusetzen wird eine WLAN-Verbindung benötigt.", - "Writer": "Drehbuchautor", - "Yes": "Ja" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "Schalte diese Funktion mit einer kleinen einmaligen Geb\u00fchr oder einem aktiven Emby Premium Abo frei.", + "MessageUnlockAppWithSupporter": "Schalte diese Funktion mit einem aktiven Emby Premium Abo frei.", + "MessageToValidateSupporter": "Wenn du eine aktive Emby Premiere Mitgliedschaft hast, stelle bitte sicher, dass du diese \u00fcber das Emby Server Dashboard eingerichtet hast (Hauptmenu -> Emby Premiere).", + "ValueSpecialEpisodeName": "Special - {0}", + "Share": "Teilen", + "Add": "Hinzuf\u00fcgen", + "ServerUpdateNeeded": "Dieser Emby Server muss aktualisiert werden. Um die neueste Version herunterzuladen, besuche bitte {0}", + "LiveTvRequiresUnlock": "Live TV ben\u00f6tigt eine aktive Emby Premiere Mitgliedschaft.", + "AttributeNew": "Neu", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Wiederholen", + "TrackCount": "{0} Titel", + "ItemCount": "{0} Eintr\u00e4ge", + "OriginalAirDateValue": "Erstausstrahlung: {0}", + "EndsAtValue": "Endet um {0}", + "HeaderSelectDate": "Datum w\u00e4hlen", + "Watched": "Gesehen", + "AirDate": "Ausstrahlungsdatum", + "Played": "Gesehen", + "ButtonOk": "Ok", + "ButtonCancel": "Abbrechen", + "AccessRestrictedTryAgainLater": "Der Zugriff ist derzeit eingeschr\u00e4nkt. Bitte versuche es sp\u00e4ter erneut.", + "ButtonGotIt": "Verstanden", + "ButtonRestart": "Neustart", + "RecordingCancelled": "Aufzeichnung abgebrochen.", + "SeriesCancelled": "Serie abgebrochen.", + "RecordingScheduled": "Aufnahme geplant.", + "SeriesRecordingScheduled": "Serien-Aufnahme geplant.", + "HeaderNewRecording": "Neue Aufnahme", + "WakeServer": "Server aufwecken", + "HeaderWakeServer": "Server aufwecken", + "AttemptingWakeServer": "Versuche Server aufwecken. Bitte warten...", + "WakeServerSuccess": "Erfolgreich!", + "HeaderCustomizeHomeScreen": "Startbildschirm konfigurieren", + "WakeServerError": "Wake On LAN Pakete wurden an deinen Server geschickt, aber wir konnten deinen Emby Server nicht erreichen. Deine Maschine braucht vielleicht etwas l\u00e4nger um aufzuwachen oder Emby Server wird zur Zeit nicht ausgef\u00fchrt.", + "Sunday": "Sonntag", + "Monday": "Montag", + "Tuesday": "Dienstag", + "Wednesday": "Mittwoch", + "Thursday": "Donnerstag", + "Friday": "Freitag", + "Saturday": "Samstag", + "Days": "Tage", + "SortByValue": "Sortieren nach {0}", + "LabelSortBy": "Sortiert nach:", + "LabelSortOrder": "Sortierreihenfolge", + "HeaderPhotoAlbums": "Fotoalben", + "Photos": "Fotos", + "HeaderAppearsOn": "Erscheint auf", + "List": "Liste", + "RecordSeries": "Serie aufnehmen", + "HeaderCinemaMode": "Kinomodus", + "HeaderCloudSync": "Cloud Synchronisation", + "Downloads": "Downloads", + "HeaderMyDownloads": "Meine Downloads", + "HeaderOfflineDownloads": "Offline Medien", + "HeaderOfflineDownloadsDescription": "Lade Medien auf deine Ger\u00e4te herunter um sie einfach offline zu nutzen.", + "CloudSyncFeatureDescription": "Synchronisiere deine Medien in die Cloud f\u00fcr ein Backup, eine Archivierung und Konvertierung.", + "LiveTvFeatureDescription": "Streame Live TV zu jeder Emby App mit einem kompatiblen TV Tuner , der auf deinem Emby Server installiert ist.", + "DvrFeatureDescription": "Plane individuelle Aufnahmen von Live-TV, Serien und mehr mit Emby DVR.", + "CinemaModeFeatureDescription": "Der Cinema Mode bringt das richtige Kinogef\u00fchl mit Trailern und eigenen Intros vor dem Hauptfilm.", + "HeaderFreeApps": "Kostenlose Emby Apps", + "FreeAppsFeatureDescription": "Genie\u00dfe Zugriff auf kostenlose Emby Apps f\u00fcr deine Ger\u00e4te.", + "HeaderBecomeProjectSupporter": "Hol dir Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Ein aktives Emby Premium Abo wird benn\u00f6tigt um automatische Serienaufnahmen zu erstellen.", + "LabelEmailAddress": "E-Mail Adresse:", + "PromoConvertRecordingsToStreamingFormat": "Konvertiere Aufnahmen automatisch in ein Streaming-freundliches Format mit Emby Premiere. Aufnahmen werden, basierend auf den Emby Server-Einstellungen, dynamisch zu MP4 oder MKV konvertiert.", + "FeatureRequiresEmbyPremiere": "Dieses Feature ben\u00f6tigt eine aktive Emby Premiere Mitgliedschaft.", + "HeaderConvertYourRecordings": "Konvertiere deine Aufnahmen", + "Record": "Aufnehmen", + "Save": "Speichern", + "Edit": "Bearbeiten", + "Download": "Download", + "Downloaded": "Heruntergeladen", + "Downloading": "L\u00e4dt herunter", + "Advanced": "Erweitert", + "Delete": "L\u00f6schen", + "HeaderDeleteItem": "L\u00f6sche Element", + "ConfirmDeleteItem": "L\u00f6schen dieses Eintrages bedeutet das L\u00f6schen der Datei und das Entfernen aus der Medien-Bibliothek. M\u00f6chtest du wirklich fortfahren?", + "Refresh": "Aktualisieren", + "RefreshQueued": "Aktualisierung eingereiht.", + "AddToCollection": "Zur Sammlung hinzuf\u00fcgen", + "HeaderAddToCollection": "Zu Sammlung hinzuf\u00fcgen", + "NewCollection": "Neue Collection", + "LabelCollection": "Sammlung:", + "Help": "Hilfe", + "LabelDisplayMode": "Bildschirmmodus:", + "Desktop": "Desktop", + "Mobile": "Mobil \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Bitte w\u00e4hle den Typ des Bildschirms auf dem Du Emby verwendest.", + "LabelDisplayLanguage": "Anzeigesprache:", + "LabelDisplayLanguageHelp": "Die \u00dcbersetzung von Emby ist ein laufendes Projekt.", + "LearnHowYouCanContribute": "Erfahre, wie du unterst\u00fctzen kannst.", + "NewCollectionHelp": "Sammlungen erm\u00f6glichen personallisierte Gruppen von Filmen oder anderen Medien.", + "SearchForCollectionInternetMetadata": "Suche im Internet nach Bildmaterial und Metadaten", + "DisplayMissingEpisodesWithinSeasons": "Zeige fehlende Episoden innerhalb von Staffeln", + "DisplayMissingEpisodesWithinSeasonsHelp": "Dies sollte auch f\u00fcr Serienbibliotheken in den Emby Server Einstellungen aktiviert sein.", + "EnableThemeSongs": "Aktiviere Titelmelodien", + "EnableBackdrops": "Aktiviere Hintergr\u00fcnde", + "EnableThemeSongsHelp": "Wenn aktiviert, wird Titelmusik w\u00e4hrend des Browsens durch die Bibliothek im Hintergrund abgespielt.", + "EnableBackdropsHelp": "Wenn aktiviert, werden w\u00e4hrend des Browsens durch die Bibliothek auf einigen Seiten passende Hintergr\u00fcnde angezeigt.", + "EnableThemeVideos": "Altiviere Titelvideos", + "EnableThemeVideosHelp": "Wenn aktiviert, wird ein Titelvideo w\u00e4hrend dem Durchsuchen durch die Bibliothek im Hintergrund abgespielt.", + "RunAtStartup": "Nach Hochfahren automatisch starten", + "LabelScreensaver": "Bildschirmschoner:", + "LabelSoundEffects": "Soundeffekte:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Beispiel: Star Wars Collection", + "MessageItemsAdded": "Eintr\u00e4ge hinzugef\u00fcgt", + "OptionNew": "Neu...", + "LabelPlaylist": "Wiedergabeliste", + "AddToPlaylist": "Hinzuf\u00fcgen zur Wiedergabeliste", + "HeaderAddToPlaylist": "Zur Wiedergabeliste hinzuf\u00fcgen", + "Subtitles": "Untertitel", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server Dashboard Theme:", + "SearchForSubtitles": "Suche nach Untertiteln", + "LabelLanguage": "Sprache:", + "Search": "Suche", + "NoSubtitleSearchResultsFound": "Keine Ergebnisse gefunden.", + "File": "Datei", + "MessageAreYouSureDeleteSubtitles": "Bist du dir sicher diese Untertitel Datei l\u00f6schen zu wollen?", + "ConfirmDeletion": "Best\u00e4tige L\u00f6schung", + "MySubtitles": "Meine Untertitel", + "MessageDownloadQueued": "Download eingereiht.", + "EditSubtitles": "Untertitel bearbeiten", + "UnlockGuide": "Guide freischalten", + "RefreshMetadata": "Aktualisiere Metadaten", + "ReplaceExistingImages": "Ersetze vorhandene Bilder", + "ReplaceAllMetadata": "Ersetze alle Metadaten", + "SearchForMissingMetadata": "Suche nach fehlenden Metadaten", + "LabelRefreshMode": "Aktualisierungsmodus:", + "NoItemsFound": "Keine Eintr\u00e4ge gefunden.", + "HeaderSaySomethingLike": "Sage etwas wie...", + "ButtonTryAgain": "Erneut versuchen", + "HeaderYouSaid": "Du sagtest...", + "MessageWeDidntRecognizeCommand": "Entschuldigung, dieses Kommando konnten wir nicht erkennen.", + "MessageIfYouBlockedVoice": "Wenn du die Sprachsteuerung f\u00fcr die App nicht erlaubt hast, musst du dies vor einem erneuten Versuch \u00e4ndern.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Nicht bewertet", + "Favorite": "Favorit", + "Like": "Mag ich", + "Dislike": "Mag ich nicht", + "RefreshDialogHelp": "Metadaten werden auf Basis der Einstellungen und Internet Services in den Emby Server Einstellungen aktualisiert.", + "Open": "\u00d6ffnen", + "Play": "Abspielen", + "AddToPlayQueue": "Zur Abspielwarteschlange hinzuf\u00fcgen", + "Shuffle": "Zufallswiedergabe", + "Identify": "Identifizieren", + "EditImages": "Bearbeite Bilder", + "EditMetadata": "Bearbeite Metadaten", + "Convert": "Konvertieren", + "Sync": "Synchronisation", + "InstantMix": "Schnellmix", + "ViewAlbum": "Zeige Album", + "ViewArtist": "Zeige Darsteller", + "QueueAllFromHere": "Setze alles von hier auf Warteschlange", + "PlayAllFromHere": "Spiele alles von hier", + "PlayFromBeginning": "Von Beginn abspielen", + "ResumeAt": "Fortsetzen bei {0}", + "RemoveFromPlaylist": "Von Wiedergabeliste entfernen", + "RemoveFromCollection": "Aus Sammlung entfernen", + "Sort": "Sortieren", + "Trailer": "Trailer", + "MarkPlayed": "Markiere \"als gesehen\"", + "MarkUnplayed": "Markiere \"als ungesehen\"", + "GroupVersions": "Gruppiere Versionen", + "PleaseSelectTwoItems": "Bitte w\u00e4hle mindestens zwei Optionen aus.", + "TryMultiSelect": "Versuche Mehrfachauswahl", + "TryMultiSelectMessage": "F\u00fcr eine Mehrfachauswahl klicke und halte ein Poster. W\u00e4hle die Eintr\u00e4ge die du bearbeiten m\u00f6chten. Versuch es!", + "HeaderConfirmRecordingCancellation": "Best\u00e4tige Aufzeichnungsabbruch", + "MessageConfirmRecordingCancellation": "Aufzeichnung abbrechen?", + "Error": "Fehler", + "VoiceInput": "Spracheingabe", + "LabelContentType": "Typ des Inhalts:", + "LabelPath": "Pfad:", + "Playlists": "Wiedergabelisten", + "LabelTitle": "Titel:", + "LabelOriginalTitle": "Original Titel:", + "LabelSortTitle": "Sortierungs Titel:", + "LabelDateAdded": "Hinzugef\u00fcgt am:", + "DateAdded": "Hinzugef\u00fcgt am", + "DatePlayed": "Gesehen am", + "ConfigureDateAdded": "Bestimme in den Bibliotheks-Einstellungen des Emby Server Dashboards, wie das Feld \"Hinzugef\u00fcgt am\" interpretiert werden soll.", + "LabelStatus": "Status:", + "LabelArtists": "Interpreten:", + "LabelArtistsHelp": "Trenne mehrere Eintr\u00e4ge durch ;", + "HeaderAlbumArtists": "Albuminterpreten", + "LabelAlbumArtists": "Alben Interpreten:", + "LabelAlbum": "Album:", + "Artists": "Interpreten", + "ImdbRating": "IMDb Bewertung", + "CommunityRating": "Community Bewertung", + "LabelCommunityRating": "Community Bewertung:", + "LabelCriticRating": "Kritiker Bewertung:", + "CriticRating": "Kritiker Bewertung", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "\u00dcbersicht:", + "LabelShortOverview": "Kurz\u00fcbersicht:", + "LabelReleaseDate": "Ver\u00f6ffentlichungsdatum:", + "LabelYear": "Jahr:", + "LabelPlaceOfBirth": "Geburtsort:", + "Aired": "Ausgestrahlt", + "LabelAirDays": "Ausstrahlungstage:", + "LabelAirTime": "Ausstrahlungszeit:", + "LabelRuntimeMinutes": "Laufzeit (Minuten):", + "LabelParentalRating": "Altersfreigabe:", + "LabelCustomRating": "Eigene Bewertung:", + "LabelOriginalAspectRatio": "Original Seitenverh\u00e4ltnis:", + "Label3DFormat": "3D Format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} Downloads", + "PerfectMatch": "Perfektes Ergbnis", + "EnableExternalVideoPlayers": "Aktiviere externe Videoplayer", + "EnableExternalVideoPlayersHelp": "Ein Men\u00fc f\u00fcr externe Videoplayer wird beim Start der Videowiedergabe angezeigt.", + "HeaderSpecialEpisodeInfo": "Spezialepisoden Information", + "LabelAirsBeforeSeason": "Ausstrahlungen vor Staffel:", + "LabelAirsAfterSeason": "Ausstrahlungen nach Staffel:", + "LabelAirsBeforeEpisode": "Ausstrahlungen vor Episode:", + "HeaderExternalIds": "Externe IDs:", + "HeaderDisplaySettings": "Anzeige Einstellungen", + "LabelDisplayOrder": "Anzeigereihenfolge:", + "Display": "Anzeige", + "Countries": "L\u00e4nder", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadaten Einstellungen", + "People": "Personen", + "LabelMetadataDownloadLanguage": "Bevorzugte Sprache f\u00fcr Downloads:", + "LabelLockItemToPreventChanges": "Sperre diesen Eintrag um zuk\u00fcnftige \u00c4nderungen zu verhindern", + "MessageLeaveEmptyToInherit": "Freilassen f\u00fcr die Vererbung von Berechtigungen oder dem systemweiten Standardwert.", + "LabelCountry": "Land:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Geburtsjahr:", + "LabelBirthDate": "Geburtsdatum:", + "LabelDeathDate": "Todesdatum:", + "LabelEndDate": "Endzeit:", + "LabelSeasonNumber": "Staffelnummer:", + "LabelEpisodeNumber": "Episodennummer:", + "LabelTrackNumber": "St\u00fcck Nummer:", + "LabelNumber": "Nummer:", + "LabelDiscNumber": "Discnummer:", + "LabelParentNumber": "Ursprungsnummer:", + "SortName": "Sortiername", + "ReleaseDate": "Ver\u00f6ffentlichungsdatum", + "Continuing": "Fortlaufend", + "Ended": "Beendent", + "HeaderEnabledFields": "Aktiviere Felder", + "HeaderEnabledFieldsHelp": "W\u00e4hle Felder ab um das \u00c4ndern von Daten zu verhindern.", + "Backdrops": "Hintergr\u00fcnde", + "Images": "Bilder", + "Runtime": "Laufzeit", + "ProductionLocations": "Drehorte", + "BirthLocation": "Geburtsort", + "ParentalRating": "Altersfreigabe", + "PlayCount": "Wiedergabez\u00e4hler", + "Name": "Name", + "Overview": "\u00dcbersicht", + "LabelType": "Typ:", + "LabelPersonRole": "Rolle:", + "LabelPersonRoleHelp": "Beispiel: Eiswagenfahrer", + "Actor": "Schauspieler", + "Composer": "Komponist", + "Director": "Regisseur", + "GuestStar": "Gaststar", + "Producer": "Produzent", + "Writer": "Drehbuchautor", + "MessageNoSyncJobsFound": "Keine Downloads gefunden. Um Downloadauftr\u00e4ge zu erstellen verwende die Downloadbuttons in der App.", + "MessageNoDownloadsFound": "Keine Offline-Downloads. Downloade deine Medien um sie offline abzuspielen indem du Download in der App anklickst.", + "InstallingPackage": "Installiere {0}", + "PackageInstallCompleted": "{0} Installation abgeschlossen", + "PackageInstallFailed": "{0} Installation fehlgeschlagen", + "PackageInstallCancelled": "{0} Installation abgebrochen", + "SeriesYearToPresent": "{0}-Heute", + "ValueOneItem": "1 Eintrag", + "ValueOneSong": "1 Lied", + "ValueSongCount": "{0} Lieder", + "ValueOneMovie": "1 Film", + "ValueMovieCount": "{0} Filme", + "ValueOneSeries": "1 Serie", + "ValueSeriesCount": "{0} Serien", + "ValueOneEpisode": "1 Episode", + "ValueEpisodeCount": "{0} Episoden", + "ValueOneGame": "1 Spiel", + "ValueGameCount": "{0} Spiele", + "ValueOneAlbum": "1 Album", + "ValueAlbumCount": "{0} Alben", + "ValueOneMusicVideo": "1 Musikvideo", + "ValueMusicVideoCount": "{0} Musikvideos", + "ValueMinutes": "{0} Minuten", + "Albums": "Alben", + "Songs": "Songs", + "Books": "B\u00fccher", + "HeaderAudioBooks": "H\u00f6rb\u00fccher", + "HeaderIdentifyItemHelp": "Gib ein oder mehrere Suchkriterien ein. Entferne Kriterien um die Suchergebnisse zu erweitern.", + "PleaseEnterNameOrId": "Bitte gib einen Namen oder eine externe Id an.", + "MessageItemSaved": "Element gespeichert", + "SearchResults": "Suchergebnisse", + "ServerNameIsRestarting": "Emby Server - {0} startet neu.", + "ServerNameIsShuttingDown": "Emby Server - {0} f\u00e4hrt herunter.", + "HeaderDeleteItems": "L\u00f6sche Objekte", + "ConfirmDeleteItems": "Das L\u00f6schen dieser Objekte l\u00f6scht die Dateien vom Laufwerk und in deiner Medienbibliothek. Bist du wirklich sicher?", + "PleaseRestartServerName": "Bitte starte Emby Server - {0} neu.", + "LabelSyncJobName": "Synchronisations-Aufgabe:", + "SyncingDots": "Synchronisieren...", + "ConvertingDots": "Konvertieren...", + "LabelQuality": "Qualit\u00e4t:", + "LabelSyncNoTargetsHelp": "Es sieht so aus als w\u00fcrdest du aktuell keine Apps verwenden, die Offline-Downloads unterst\u00fctzen.", + "DownloadingDots": "L\u00e4dt herunter...", + "HeaderSyncRequiresSub": "Downloads ben\u00f6tigen ein aktives Emby Premiere Abonnement.", + "LearnMore": "Erfahre mehr", + "LabelProfile": "Profil:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Konvertiere nur ungesehen Videos", + "SyncUnwatchedVideosOnly": "Lade nur ungesehene Videos herunter", + "ConvertUnwatchedVideosOnlyHelp": "Nur ungesehene Videos werden konvertiert.", + "SyncUnwatchedVideosOnlyHelp": "Nur ungesehene Video werden heruntergeladen. Videos werden entfernt sobald diese auf dem Ger\u00e4t angeschaut wurden.", + "AutomaticallySyncNewContent": "Lade neue Inhalte automatisch herunter", + "AutomaticallySyncNewContentHelp": "Neu zu diesem Ordner hinzugef\u00fcgte Inhalte werden automatisch auf das Ger\u00e4t heruntergeladen.", + "AutomaticallyConvertNewContent": "Konvertiere neue Inhalte automatisch", + "AutomaticallyConvertNewContentHelp": "Neue Inhalte in diesem Ordner werden automatisch konveriert.", + "LabelItemLimit": "Maximale Anzahl:", + "ConvertItemLimitHelp": "Optional. Lege die maximale Anzahl der zu konvertierenden Dateien fest.", + "DownloadItemLimitHelp": "Optional. Lege die maximale Anzahl der herunterzuladenden Dateien fest.", + "PleaseSelectDeviceToSyncTo": "Bitte w\u00e4hle ein Download-Zielger\u00e4t.", + "Screenshots": "Screenshots", + "MoveRight": "Nach rechts bewegen", + "MoveLeft": "Nach links bewegen", + "ConfirmDeleteImage": "Bild l\u00f6schen?", + "HeaderEditImages": "Bilder bearbeiten", + "Settings": "Einstellungen", + "ShowIndicatorsFor": "Zeige Indikatoren f\u00fcr:", + "NewEpisodes": "Neue Episoden", + "Episodes": "Episoden", + "HDPrograms": "HD Programme", + "Programs": "Programme", + "LiveBroadcasts": "Live\u00fcbertragungen", + "Premieres": "Premieren", + "RepeatEpisodes": "Wiederholung Episoden", + "DvrSubscriptionRequired": "Emby DVR ben\u00f6tigt eine aktive Emby Premiere Mitgliedschaft.", + "HeaderCancelRecording": "Aufnahme abbrechen", + "CancelRecording": "Aufnahme abbrechen", + "HeaderKeepRecording": "Aufnahme behalten", + "HeaderCancelSeries": "Serie abbrechen", + "HeaderKeepSeries": "Serie behalten", + "HeaderLearnMore": "Erfahre mehr", + "DeleteMedia": "Medien l\u00f6schen", + "SeriesSettings": "Serieneinstellungen", + "HeaderRecordingOptions": "Aufnahmeeinstellungen", + "CancelSeries": "Serien abbrechen", + "DoNotRecord": "Nicht aufnehmen", + "HeaderSeriesOptions": "Serienoptionen", + "LabelChannels": "Kan\u00e4le:", + "ChannelNameOnly": "Nur Kanal {0}", + "Anytime": "Jederzeit", + "AnyLanguage": "Jede Sprache", + "AroundTime": "Um {0}", + "All": "Alle", + "AllChannels": "Alle Kan\u00e4le:", + "LabelRecord": "Aufnahme:", + "NewEpisodesOnly": "Nur neue Episoden", + "AllEpisodes": "Alle Episoden", + "LabelStartWhenPossible": "Starte wenn m\u00f6glich:", + "LabelStopWhenPossible": "Stoppe wenn m\u00f6glich", + "MinutesBefore": "Minuten vor", + "MinutesAfter": "Minuten nach", + "SkipEpisodesAlreadyInMyLibrary": "Nehme keine Episoden auf, die schon in meiner Bibliothek verf\u00fcgbar sind.", + "SkipEpisodesAlreadyInMyLibraryHelp": "Episoden werden mittels Staffel- und Episodennummer verglichen, wenn verf\u00fcgbar.", + "LabelKeepUpTo": "Fortf\u00fchren:", + "AsManyAsPossible": "So viele wie m\u00f6glich", + "DefaultErrorMessage": "Es gab einen Fehler beim verarbeiten der Anfrage. Bitte versuche es sp\u00e4ter erneut.", + "LabelKeep:": "Behalten:", + "UntilIDelete": "Bis ich l\u00f6sche", + "UntilSpaceNeeded": "Bis Speicherplatz ben\u00f6tigt wird", + "Categories": "Kategorien", + "Sports": "Sport", + "News": "Nachrichten", + "Movies": "Filme", + "Kids": "Kinder", + "EnableColorCodedBackgrounds": "Aktiviere farbige Hintergr\u00fcnde", + "SortChannelsBy": "Sortiere Kan\u00e4le nach:", + "RecentlyWatched": "K\u00fcrzlich gesehen", + "ChannelNumber": "Kanalnummer", + "HeaderBenefitsEmbyPremiere": "Vorteile von Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "Genie\u00dfe eine Minute Wiedergabe. Danke, dass du Emby ausprobierst.", + "HeaderTryPlayback": "Wiedergabe ausprobieren", + "HowDidYouPay": "Wie hast Du bezahlt?", + "IHaveEmbyPremiere": "Ich besitze Emby Premiere", + "IPurchasedThisApp": "Ich habe diese App gekauft", + "ButtonRestorePreviousPurchase": "Kauf wiederherstellen", + "ButtonUnlockWithPurchase": "Freischalten durch Kauf", + "ButtonUnlockPrice": "{0} freischalten", + "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", + "Items": "Eintr\u00e4ge", + "OneChannel": "Ein Kanal", + "ConfirmRemoveDownload": "Download entfernen?", + "RemoveDownload": "Download entfernen", + "KeepDownload": "Download behalten", + "AddedOnValue": "Hinzugef\u00fcgt {0}", + "RemovingFromDevice": "Vom Ger\u00e4t entfernen", + "KeepOnDevice": "Auf Ger\u00e4t behalten", + "CancelDownload": "Download abbrechen", + "SyncJobItemStatusReadyToTransfer": "Fertig zum Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Vom Ger\u00e4t entfernen", + "SyncJobItemStatusQueued": "In Warteschlange", + "SyncJobItemStatusConverting": "Konvertiere", + "SyncJobItemStatusTransferring": "\u00dcbertrage", + "SyncJobItemStatusSynced": "Heruntergeladen", + "SyncJobItemStatusFailed": "Fehlgeschlagen", + "SyncJobItemStatusRemovedFromDevice": "Vom Ger\u00e4t entfernt", + "SyncJobItemStatusCancelled": "Abgebrochen", + "Retry": "Wiederholen", + "HeaderMyDevice": "Mein Ger\u00e4t", + "Continue": "Fortfahren", + "ContinueInSecondsValue": "Fortfahren in {0} Sekunden.", + "HeaderRemoteControl": "Fernsteuerung", + "Disconnect": "Verbindung trennen", + "EnableDisplayMirroring": "Aktiviere Display-Weiterleitung", + "HeaderPlayOn": "Abspielen auf", + "Quality": "Qualit\u00e4t", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "Um ihren voherigen Kauf wiederherzustellen, versichern Sie sich bitte, dass Sie auf dem Ger\u00e4t mit dem selben Google (oder Amazon) Account angemeldet sind, mit dem Sie die Kauf urspr\u00fcnglich get\u00e4tigt haben. Stellen Sie sicher, dass der Appstore aktiviert und nicht durch eine Kindersicherung eingeschr\u00e4nkt ist und vergewissern Sie sich, dass sie \u00fcber eine aktive Internetverbindung verf\u00fcgen. Sie m\u00fcssen dies nur einmal tun, um ihren vorherigen Kauf wiederherzustellen.", + "AspectRatio": "Seitenverh\u00e4ltnis", + "Original": "Original", + "Fill": "Ausf\u00fcllen", + "BestFit": "Beste \u00dcbereinstimmung", + "MessageNoServersAvailableToConnect": "Es steht kein verbindungsbereiter Server zur Verf\u00fcgung. Wenn du eingeladen wurdest, vergewissere dich, dass du die Einladung weiter unten akzeptierst oder den Link in der E-Mail angeklickt hast.", + "MessagePlayAccessRestricted": "Das Abspielen dieses Inhaltes ist derzeit eingeschr\u00e4nkt. Bitte kontaktiere deinen Emby Server-Administrator f\u00fcr weitere Informationen.", + "Accept": "Akzeptieren", + "Reject": "Ablehnen", + "Connect": "Verbinde", + "HeaderMyMedia": "Meine Medien", + "HeaderMyMediaSmall": "Meine Medien (Klein)", + "LatestFromLibrary": "Neueste {0}", + "ContinueWatching": "Weiterschauen", + "HeaderLatestChannelMedia": "Neueste Channelinhalte", + "HeaderContinueWatching": "Weiterschauen", + "HeaderContinueListening": "Weiterh\u00f6ren", + "HeaderActiveRecordings": "Aktive Aufnahmen", + "HeaderLatestRecordings": "Neueste Aufnahmen", + "LabelSyncTo": "Synchronisiere mit:", + "LabelConvertTo": "Konvertiere nach:", + "Next": "N\u00e4chstes", + "LabelSource": "Quelle:", + "LabelVersion": "Version:", + "AllLanguages": "Alle Sprachen", + "Previous": "Vorheriges", + "HeaderNextUp": "Als N\u00e4chstes", + "HeaderLatestFrom": "Neuestes von {0}", + "LabelHomeScreenSectionValue": "Startseitenbereich {0}:", + "SettingsSaved": "Einstellungen gespeichert.", + "None": "Keines", + "More": "Mehr", + "Up": "Hoch", + "Down": "Runter", + "Home": "Home", + "Favorites": "Favoriten", + "HeaderHomeScreen": "Startseite", + "HeaderLatestChannelItems": "Neueste Channelinhalte", + "HeaderLibraryOrder": "Bibliotheksreihenfolge", + "HideWatchedContentFromLatestMedia": "Verberge gesehene Inhalte von neuesten Medien.", + "HeaderOnNow": "Gerade l\u00e4uft", + "HeaderPlaybackError": "Wiedergabefehler", + "PlaybackErrorNotAllowed": "Die verf\u00fcgst derzeit \u00fcber keine Berechtigung um diesen Inhalt abzuspielen. Bitte kontaktiere deinen Systemadministrator f\u00fcr weitere Informationen.", + "PlaybackErrorNoCompatibleStream": "Derzeit sind keine kompatiblen Stream verf\u00fcgbar. Bitte versuche es sp\u00e4ter nochmal oder kontaktiere deinen Systemadministrator f\u00fcr weitere Informationen.", + "PlaybackErrorPlaceHolder": "Bitte lege die Disc ein um das Video abzuspielen.", + "Guide": "TV Guide", + "Suggestions": "Empfehlungen", + "HeaderFavoriteCollections": "Lieblingssammlungen", + "HeaderFavoritePlaylists": "Lieblingswiedergabelisten", + "Collections": "Sammlungen", + "LabelSelectFolderGroups": "Gruppiere Inhalte von folgenden Verzeichnissen automatisch zu Ansichten wie beispielsweise Filme, Musik und TV:", + "LabelSelectFolderGroupsHelp": "Verzeichnisse die nicht markiert sind werden alleine mit ihren eigenen Ansichten angezeigt.", + "Folders": "Verzeichnisse", + "DisplayInOtherHomeScreenSections": "Zeige auf dem Homescreen Bereiche wie 'Neueste Medien' oder 'Weiterschauen'", + "DisplayInMyMedia": "Zeige auf Homescreen", + "Shows": "Serien", + "HeaderLibraryFolders": "Bibliotheksverzeichnisse", + "HeaderTermsOfPurchase": "Bestellungsbedingungen", + "PrivacyPolicy": "Datenschutzbestimmungen", + "TermsOfUse": "Nutzungsbedingungen", + "RepeatMode": "Wiederholungsmodus", + "RepeatOne": "Dieses wiederholen", + "RepeatAll": "Alles wiederholen", + "LabelDefaultScreen": "Standardscreen:", + "ConfirmEndPlayerSession": "M\u00f6chtest du Emby auf {0} beenden?", + "Yes": "Ja", + "No": "Nein", + "LiveTV": "Live TV", + "Schedule": "Zeitplan", + "Recordings": "Aufnahmen", + "MarkWatched": "Als gesehen markieren", + "ScanForNewAndUpdatedFiles": "Scanne nach neuen und aktualisierten Dateien", + "DirectStreamHelp1": "Das Medium ist mit dem Abspielger\u00e4t kompatibel bzgl. Aufl\u00f6sung und Codecs (H.264, AC3, etc.), besitzt jedoch einen inkompatiblen Dateicontainer (.mkv, .avi, .wmv, etc.). Das Video wird in Echtzeit neugepackt bevor es zum Abspielger\u00e4t gestreamt wird.", + "DirectStreamHelp2": "Direktes Streaming von Dateien ben\u00f6tigt sehr wenig Rechenleistung ohne Verlust der Videoqualit\u00e4t.", + "MediaIsBeingConverted": "Das Medium wird in ein Format konvertiert, das mit dem Abspielger\u00e4t kompatibel ist.", + "StatsForNerds": "Statistiken f\u00fcr T\u00fcftler", + "LabelReasonForTranscoding": "Grund f\u00fcr die Transkodierung:", + "DirectPlaying": "Direktes Abspielen", + "DirectStreaming": "Direktes Streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Medienbitrate \u00fcberschreitet das Limit.", + "VideoCodecNotSupported": "Video Codec nicht unterst\u00fctzt", + "AudioCodecNotSupported": "Audio Codec nicht unterst\u00fctzt", + "SubtitleCodecNotSupported": "Untertitelformat nicht unterst\u00fctzt", + "DirectPlayError": "Fehler bei der direkten Wiedergabe", + "ContainerNotSupported": "Container nicht unterst\u00fctzt", + "VideoLevelNotSupported": "Video Level nicht unterst\u00fctzt", + "AudioBitrateNotSupported": "Audio Bitrate nicht unterst\u00fctzt", + "AudioChannelsNotSupported": "Audio Kan\u00e4le nicht unterst\u00fctzt", + "VideoResolutionNotSupported": "Video Aufl\u00f6sung nicht unterst\u00fctzt", + "AudioProfileNotSupported": "Audio Profil nicht unterst\u00fctzt", + "AudioSampleRateNotSupported": "Audio Sample Rate nicht unterst\u00fctzt", + "AnamorphicVideoNotSupported": "Anamorphes Video nicht unterst\u00fctzt", + "InterlacedVideoNotSupported": "Interlaced Video nicht unterst\u00fctzt", + "SecondaryAudioNotSupported": "Tonspurwechsel nicht unterst\u00fctzt", + "ErrorRemovingEmbyConnectAccount": "Fehler beim Entfernen des Emby Connect Kontos. Bitte stelle sicher, dass du \u00fcber eine aktive Internetverbindung verf\u00fcgst und versuche es erneut.", + "HeaderEmbyAccountRemoved": "Emby Konto entfernt", + "MessageEmbyAccontRemoved": "Das Emby Konto wurde von diesem Benutzer entfernt.", + "HeaderInvitationSent": "Einladung verschickt", + "MessageInvitationSentToUser": "Eine E-Mail mit der Einladung zum Sharing ist an {0} geschickt worden.", + "MessageInvitationSentToNewUser": "Eine Email wurde an {0} mit einer Einladung zur Anmeldung an Emby gesendet.", + "GuestUserNotFound": "Benutzer nicht gefunden. Bitte stelle die korrekte Schreibweise sicher und versuche es erneut. Du kannst auch die Emailadresse verwenden.", + "ErrorReachingEmbyConnect": "Fehler bei der Verbindung zum Emby Connect Server. Stelle bitte sicher, dass du \u00fcber eine aktive Internetverbindung verf\u00fcgst und versuche es erneut.", + "ErrorAddingEmbyConnectAccount1": "Ein Fehler trat beim hinzuf\u00fcgen des Emby-Connect Kontos auf. Hast du bereits ein Emby Konto? Melde dich hier an: {0}.", + "ErrorAddingEmbyConnectAccount2": "Wenn du immer noch ein Problem hast, sende bitte eine E-Mail an {0} von der E-Mail-Adresse die du mit dem Emby-Account nutzt.", + "ErrorAddingGuestAccount1": "Ein Fehler trat beim Hinzuf\u00fcgen des Emby Connect Kontos auf. Hat Ihr Gast ein Emby Konto erstellt? Sie k\u00f6nnen sich hier anmelden {0}.", + "ErrorAddingGuestAccount2": "Wenn du immer noch ein Problem hast, sende bitte eine E-Mail an {0} mit deiner E-Mail-Adresse und die der anderen als Inhalt.", + "MessageEmbyAccountAdded": "Das Emby Konto wurde diesem Benutzer hinzugef\u00fcgt.", + "MessagePendingEmbyAccountAdded": "Das Emby Konto wurde diesem Benutzer hinzugef\u00fcgt. Eine Emails wird an den Besitzer dieses Kontos gesendet. Die Einladung muss mit einem Klick auf den Link in der Email best\u00e4tigt werden.", + "HeaderEmbyAccountAdded": "Emby Konto hinzugef\u00fcgt", + "LabelSubtitlePlaybackMode": "Untertitelmodus:", + "ErrorDeletingItem": "Fehler beim L\u00f6schen des Mediums vom Emby Server. Bitte stelle sicher dass der Emby Server Schreibzugriff auf den Dateiordner hat und versuche es erneut.", + "NoSubtitles": "Keine Untertitel", + "Default": "Standard", + "Absolute": "Absolut", + "Smart": "Smart", + "Small": "Klein", + "Smaller": "Kleiner", + "Medium": "Mittel", + "Large": "Gro\u00df", + "ExtraLarge": "Extragro\u00df", + "OnlyForcedSubtitles": "Nur erzwungene Untertitel", + "AlwaysPlaySubtitles": "Untertitel immer anzeigen", + "DefaultSubtitlesHelp": "Untertitel werden gem\u00e4\u00df der Standard- und Erzwungen-Ansicht aus den eingebetteten Metadaten geladen. Spracheinstellungen werden zur Verf\u00fcgung gestellt, wenn mehrere Sprachen verf\u00fcgbar sind.", + "SmartSubtitlesHelp": "Untertitel, die den Spracheinstellungen entsprechen, werden nur bei einer Tonspur in fremder Sprache heruntergeladen.", + "HeaderSubtitleSettings": "Untertiteleinstellungen", + "HeaderSubtitleAppearance": "Untertiteldarstellung", + "OnlyForcedSubtitlesHelp": "Nur Untertitel, die als erzwungen markiert wurden, werden geladen.", + "AlwaysPlaySubtitlesHelp": "Untertitel die den Spracheinstellungen entsprechen werden unabh\u00e4ngig von der Tonspursprache geladen.", + "NoSubtitlesHelp": "Untertitel werden standardm\u00e4\u00dfig nicht geladen. Sie k\u00f6nnen aber w\u00e4hrend der Wiedergabe manuell aktiviert werden.", + "LabelPreferredSubtitleLanguage": "Bevorzugte Untertitelsprache:", + "LabelTextSize": "Textgr\u00f6\u00dfe", + "TheseSettingsAffectSubtitlesOnThisDevice": "Diese Einstellungen beeinflussen Untertitel auf diesem Ger\u00e4t", + "LabelDropShadow": "Schlagschatten:", + "LabelTextBackgroundColor": "Hintergrundfarbe des Textes:", + "LabelWindowBackgroundColor": "Hintergrundfarbe des Textes:", + "LabelFont": "Schriftart:", + "LabelTextColor": "Textfarbe:", + "Raised": "Angehoben", + "Depressed": "Gedr\u00fcckt", + "Uniform": "Einheitlich", + "DropShadow": "Schlagschatten", + "SmallCaps": "Kapit\u00e4lchen", + "SubtitleAppearanceSettingsDisclaimer": "Diese Einstellungen werden nicht auf grafische Untertitel (PGS, DVD, etc.) oder Untertitel mit eingebettetem Style-Elementen (ASS\/SSA) angewendet.", + "LabelBurnSubtitles": "Untertitel einbrennen:", + "OnlyImageFormats": "Nur Bildformate (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Legt fest, ob der Server die Untertitel basierend auf deren Format einbrennen soll w\u00e4hrend der Videokonvertierung. Die Vermeidung des Einbrennen von Untertiteln verbessert die Serverperformance. W\u00e4hle Auto, um Bildfomate (z.B. VOBSUB, PGS, SUB\/IDX, etc.) sowie bestimmte ASS\/SSA-Untertitel einbrennen zu lassen.", + "AllComplexFormats": "Alle komplexen Formate (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Diese Einstellungen werden auch auf jede Chromecast-Wiedergabe angewendet, die von diesem Ger\u00e4t gestartet wird.", + "HeaderWaitingForWifi": "Warte auf WLAN", + "WifiRequiredToDownload": "Um den Download fortzusetzen wird eine WLAN-Verbindung ben\u00f6tigt.", + "HeaderDownloadSettings": "Downloadeinstellungen", + "Hide": "Verstecke", + "HeaderStartNow": "Starte jetzt", + "HeaderNextVideoPlayingInValue": "N\u00e4chstes Video wird abgespielt in {0}", + "HeaderNextEpisodePlayingInValue": "N\u00e4chste Episode wird abgespielt in {0}", + "HeaderSecondsValue": "{0} Sekunden", + "AudioBitDepthNotSupported": "Audiobittiefe nicht unterst\u00fctzt", + "VideoProfileNotSupported": "Videoprofil nicht unterst\u00fctzt", + "VideoFramerateNotSupported": "Videoframerate nicht unterst\u00fctzt", + "VideoBitDepthNotSupported": "Videobittiefe nicht unterst\u00fctzt", + "RefFramesNotSupported": "Anzahl der Videoreferenzframes nicht unterst\u00fctzt", + "ErrorConnectServerUnreachable": "Es gab einen Fehler bei bei der Ausf\u00fchrung des Funktion. Dein Server ist nicht in der Lage unsere Emby-Connect-Server zu erreichen um {0}. Stelle bitte sicher, dass dein Server eine aktive Internetverbindung hat und die Kommunikations durch die Firewall oder andere installierte Sicherheitssoftware erlaubt wurde.", + "StopRecording": "Aufnahme stoppen", + "HeaderStopRecording": "Aufnahme stoppen", + "ManageRecording": "Aufnahme verwalten", + "LabelDropImageHere": "Fotos hierher ziehen oder klicken im zu browsen.", + "MessageFileReadError": "Es gab einen Fehler beim Lesen der Datei. Bitte versuche es erneut.", + "Browse": "Bl\u00e4ttern", + "HeaderUploadImage": "Bild hochladen", + "HeaderAddUpdateImage": "Bild hinzuf\u00fcgen\/aktualisieren", + "LabelImageType": "Bildtyp:", + "Upload": "Hochladen", + "Primary": "Prim\u00e4r", + "Art": "Art", + "Backdrop": "Hintergrund", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (R\u00fcckseite)", + "Disc": "Disk", + "Logo": "Logo", + "Menu": "Men\u00fc", + "Screenshot": "Bildschirmfoto", + "Thumb": "Thumb", + "ValueSeconds": "{0} Sekunden", + "HeaderAudioSettings": "Audioeinstellungen", + "LabelAudioLanguagePreference": "Bevorzugte Audiosprache:", + "LabelPlayDefaultAudioTrack": "Spiele unabh\u00e4ngig von der Sprache die Standardtonspur", + "HeaderVideoQuality": "Videoqualit\u00e4t", + "CinemaModeConfigurationHelp": "Der Kinomodus bringt das Kinoerlebnis direkt in dein Wohnzimmer, mit der F\u00e4higkeit Trailer und benutzerdefinierte Intros vor dem Hauptfilm abzuspielen.", + "EnableNextVideoInfoOverlay": "Aktiviere \"Next-Video-Info\" w\u00e4hrend der Wiedergabe", + "EnableNextVideoInfoOverlayHelp": "Zeige Informationen \u00fcber das n\u00e4chste abzuspielende Video in der aktuellen Abspielliste am Ende des laufenden Videos an.", + "PlayNextEpisodeAutomatically": "Starte n\u00e4chste Episode automatisch", + "LabelMaxChromecastBitrate": "Max Chromcast Datenrate:", + "LabelSkipBackLength": "Sprungweite r\u00fcckw\u00e4rts:", + "LabelSkipForwardLength": "Sprungweite vorw\u00e4rts:", + "EnableCinemaMode": "Aktiviere den Kino-Modus", + "LabelInternetQuality": "Internetqualit\u00e4t:", + "HeaderMusicQuality": "Musikqualit\u00e4t", + "LabelHomeNetworkQuality": "Heimnetzwerkqualit\u00e4t:", + "HeaderLatestMedia": "Neueste Medien", + "HeaderRestartingEmbyServer": "Emby Server neu starten", + "RestartPleaseWaitMessage": "Warte bitte bis der Emby Server heruntergefahren und neu gestartet wurde. Dieser Vorgang dauert 1 bis 2 Minuten.", + "PlayNext": "Spiele als N\u00e4chstes ab", + "AllowSeasonalThemes": "Erlaube automatische Saison-Themes", + "AllowSeasonalThemesHelp": "Wenn aktiviert, werden Saison-Themes von Zeit zu Zeit deine Theme-Einstellungen \u00fcberschreiben.", + "AutoBasedOnLanguageSetting": "Automatisch (basierend auf Spracheinstellung)", + "LabelDateTimeLocale": "Datum\/Zeit lokal:", + "DirectorValue": "Regisseur: {0}", + "DirectorsValue": "Regisseure: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Untertitel:", + "Off": "Aus", + "ShowTitle": "Zeige Titel", + "ShowYear": "Zeige Jahr", + "Filters": "Filter", + "Unplayed": "Ungesehen", + "LabelTVHomeScreen": "TV-Mode Startseite", + "Horizontal": "Horizontal", + "Vertical": "Vertikal", + "GroupBySeries": "Nach Serien gruppieren", + "HeaderVideoType": "Videotyp:", + "HeaderSeriesStatus": "Serienstatus:", + "Features": "Features", + "Trailers": "Trailer", + "Extras": "Extras", + "ThemeSongs": "Titelsongs", + "ThemeVideos": "Titelvideos", + "HeaderFavoriteMovies": "Lieblingsfilme", + "HeaderFavoriteShows": "Lieblingsserien", + "HeaderFavoriteEpisodes": "Lieblingsepisoden", + "HeaderFavoriteVideos": "Lieblingsvideos", + "HeaderFavoriteGames": "Lieblingsspiele", + "HeaderFavoriteArtists": "Lieblingsk\u00fcnstler", + "HeaderFavoriteAlbums": "Lieblingsalben", + "HeaderFavoriteSongs": "Lieblingssongs", + "Ascending": "Aufsteigend", + "Descending": "Absteigend", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Farbraum", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Sortiere Episoden nach Ausstrahlungsdatum, DVD Reihenfolge oder absoluter Nummerierung.", + "PlaybackSettingsIntro": "Um die Wiedergabeeinstellungen zu \u00e4ndern, stoppen Sie die Wiedergabe und klicken Sie auf Ihr Benutzer-Icon in der oberen rechten Ecke der App.", + "SubtitleSettingsIntro": "Um das Aussehen der Untertitel und die Spracheinstellungen zu \u00e4ndern, stoppen Sie die Wiedergabe und klicken Sie auf Ihr Benutzer-Icon in der oberen rechten Ecke der App." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/el.json b/src/bower_components/emby-webcomponents/strings/el.json index d27a8e89cb..cb88caa75e 100644 --- a/src/bower_components/emby-webcomponents/strings/el.json +++ b/src/bower_components/emby-webcomponents/strings/el.json @@ -1,685 +1,689 @@ { - "Absolute": "Απόλυτο", - "Accept": "Αποδοχή", - "AccessRestrictedTryAgainLater": "Η πρόσβαση είναι επί του παρόντος περιορισμένη. Παρακαλώ δοκιμάστε ξανά αργότερα.", - "Actor": "Ηθοποιός", - "Add": "Προσθήκη", - "AddToCollection": "Πρόσθεσε στη συλλογή", - "AddToPlayQueue": "Προσθήκη στην ουρά αναπαραγωγής", - "AddToPlaylist": "Πρόσθεσε σε λίστα", - "AddedOnValue": "Προστέθηκε {0}", - "Advanced": "Για προχωρημένους", - "AirDate": "Ημερομηνία προβολής", - "Aired": "Προβλήθηκε", - "Albums": "Αλμπουμς", - "All": "Όλα", - "AllChannels": "Όλα τα κανάλια", - "AllComplexFormats": "Όλες οι σύνθετες μορφές (ASS, SSA, VOBSUB, PGS, SUB / IDX κ.λπ.)", - "AllEpisodes": "Ολα τα επεισόδια", - "AllLanguages": "Όλες οι γλώσσες", - "AllowSeasonalThemes": "Ενεργοποίηση εποχιακών θεμάτων", - "AllowSeasonalThemesHelp": "Εάν είναι ενεργοποιημένο, τα εποχιακά θέματα κατά καιρούς θα αντικαταστήσουν τη ρύθμιση θέματος.", - "AlwaysPlaySubtitles": "Πάντα αναπαραγωγή Υποτίτλων", - "AlwaysPlaySubtitlesHelp": "Οι υπότιτλοι που ταιριάζουν με τις προτιμήσεις γλώσσας θα φορτωθούν ανεξάρτητα από τη γλώσσα του ήχου.", - "AnamorphicVideoNotSupported": "Το αναμορφωτικό βίντεο δεν υποστηρίζεται", - "AndroidUnlockRestoreHelp": "Για να επαναφέρετε την προηγούμενη αγορά σας, βεβαιωθείτε ότι έχετε συνδεθεί στη συσκευή με τον ίδιο λογαριασμό Google (ή Amazon) που πραγματοποίησε αρχικά την αγορά. Βεβαιωθείτε ότι το κατάστημα εφαρμογών είναι ενεργοποιημένο και δεν περιορίζεται από κανένα γονικό έλεγχο και βεβαιωθείτε ότι έχετε ενεργή σύνδεση στο διαδίκτυο. Θα χρειαστεί να το κάνετε μόνο μία φορά για να επαναφέρετε την προηγούμενη αγορά σας.", - "AnyLanguage": "Οποιαδήποτε γλώσσα", - "Anytime": "Οποτεδήποτε", - "AroundTime": "Περίπου {0}", - "Art": "Τέχνη", - "Artists": "Καλλιτέχνες", - "AsManyAsPossible": "Οσο το δυνατον περισσοτερα", - "Ascending": "Αύξουσα", - "AspectRatio": "Αρχικός λόγος διαστάσεων:", - "AttemptingWakeServer": "Ενεργοποίηση server σε εξέλιξη. Παρακαλώ περιμένετε...", - "AttributeNew": "Νέο", - "AudioBitDepthNotSupported": "Το βάθος bitrate ήχου δεν υποστηρίζεται", - "AudioBitrateNotSupported": "Το bitrate ήχου δεν υποστηρίζεται", - "AudioChannelsNotSupported": "Τα κανάλια ήχου δεν υποστηρίζονται", - "AudioCodecNotSupported": "Ο κωδικοποιητής ήχου δεν υποστηρίζεται", - "AudioProfileNotSupported": "Το προφίλ ήχου δεν υποστηρίζεται", - "AudioSampleRateNotSupported": "Δεν υποστηρίζεται το ποσοστό δειγματοληψίας ήχου", - "Auto": "Αυτόματο", - "AutoBasedOnLanguageSetting": "Αυτόματα (με βάση τη ρύθμιση γλώσσας)", - "AutomaticallyConvertNewContent": "Αυτόματη μετατροπή νέου περιεχομένου", - "AutomaticallyConvertNewContentHelp": "Το νέο περιεχόμενο που προστίθεται σε αυτόν το φάκελο θα μετατέπεται αυτόματα.", - "AutomaticallySyncNewContent": "Αυτόματη λήψη νέου περιεχομένου", - "AutomaticallySyncNewContentHelp": "Το νέο περιεχόμενο που προστίθεται σε αυτόν το φάκελο θα μεταφορτωθεί αυτόματα στη συσκευή.", - "Backdrop": "Φόντο", - "Backdrops": "Σκηνικά", - "Banner": "Πανό", - "BestFit": "Ταιριάζει καλύτερα", - "BirthLocation": "Τόπος γέννησης:", - "Books": "Βιβλία", - "Box": "Κουτί", - "BoxRear": "Box (rear)", - "Browse": "Αναζητήστε", - "BurnSubtitlesHelp": "Καθορίζει αν ο διακομιστής πρέπει να εγγράψει στους υπότιτλους κατά τη μετατροπή βίντεο ανάλογα με τη μορφή των υπότιτλων. Η αποφυγή της εγγραφής στους υπότιτλους θα βελτιώσει την απόδοση του διακομιστή. Επιλέξτε Αυτόματα για να εγγράψετε μορφές βασισμένες σε εικόνες (π.χ. VOBSUB, PGS, SUB / IDX κ.λπ.) καθώς και ορισμένους υπότιτλους ASS / SSA", - "ButtonCancel": "Ακύρωση ", - "ButtonGotIt": "Το κατάλαβα", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Αναπαραγωγή για ένα λεπτό", - "ButtonRestart": "Επανεκκίνηση", - "ButtonRestorePreviousPurchase": "Επαναφορά αγοράς", - "ButtonTryAgain": "Προσπαθήστε ξανά", - "ButtonUnlockPrice": "Ξεκλείδωμα {0}", - "ButtonUnlockWithPurchase": "Ξεκλειδώστε με την αγορά", - "CancelDownload": "Ακύρωση λήψης", - "CancelRecording": "Ακύρωση Εγγραφής", - "CancelSeries": "Ακύρωση Σειράς", - "Categories": "Κατηγορίες", - "ChannelNameOnly": "Μόνο το {0} κανάλι", - "ChannelNumber": "Αριθμός καναλιού", - "CinemaModeConfigurationHelp": "Η λειτουργία Κινηματογράφου σάς προσφέρει την πραγματική κινηματογραφική εμπειρία με τρέιλερ και προσαρμοσμένα intros πριν από τη λειτουργία.", - "CinemaModeFeatureDescription": "Η λειτουργία Κινηματογράφου σάς προσφέρει την πραγματική κινηματογραφική εμπειρία με ρυμουλκούμενα και προσαρμοσμένες intros πριν από τη λειτουργία.", - "CloudSyncFeatureDescription": "Συγχρονίστε τα πολυμέσα σας στο cloud για εύκολη δημιουργία αντιγράφων ασφαλείας, αρχειοθέτηση και μετατροπή.", - "Collections": "Συλλογές", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Χρωματικός χώρος", - "ColorTransfer": "Μεταφορά χρώματος", - "CommunityRating": "Βαθμολογία Κοινότητας", - "Composer": "Συνθέτης", - "ConfigureDateAdded": "Ρυθμίστε τη ρύθμιση του τρόπου με τον οποίο προσδιορίζεται η ημερομηνία προσθήκης στον πίνακα ελέγχου του Jellyfin Server στις Ρυθμίσεις βιβλιοθήκης", - "ConfirmDeleteImage": "Διαγραφή εικόνας;", - "ConfirmDeleteItem": "Η διαγραφή αυτού του στοιχείου θα το διαγράψει τόσο από το σύστημα αρχείων όσο και από τη βιβλιοθήκη πολυμέσων σας. Είστε βέβαιοι ότι θέλετε να συνεχίσετε;", - "ConfirmDeleteItems": "Η διαγραφή αυτών των στοιχείων θα τα διαγράψει τόσο από το σύστημα αρχείων όσο και από τη βιβλιοθήκη πολυμέσων σας. Είστε βέβαιοι ότι θέλετε να συνεχίσετε;", - "ConfirmDeletion": "Επιβεβαίωση Διαγραφής", - "ConfirmEndPlayerSession": "Θέλετε να κλείσετε τον Jellyfin στη συσκευή;", - "ConfirmRemoveDownload": "Διαγραφή λήψης;", - "Connect": "Σύνδεση", - "ContainerBitrateExceedsLimit": "Το bitrate μέσων δεδομένων υπερβαίνει το όριο.", - "ContainerNotSupported": "Το κοντέινερ δεν υποστηρίζεται", - "Continue": "Συνέχεια", - "ContinueInSecondsValue": "Συνεχίστε σε {0} δευτερόλεπτα.", - "ContinueWatching": "Συνεχίστε να παρακολουθείτε", - "Continuing": "Συνέχιση", - "Convert": "Μετατροπή", - "ConvertItemLimitHelp": "Προαιρετικό. Ορίστε ένα όριο στον αριθμό των στοιχείων που θα μετατραπούν.", - "ConvertUnwatchedVideosOnly": "Μετατροπή μόνο των βίντεο που δεν έχω παρακολουθήσει", - "ConvertUnwatchedVideosOnlyHelp": "Μόνο τα βίντεο που δεν έχω παρακολουθήσει θα μετατραπούν.", - "ConvertingDots": "Μετατροπή...", - "Countries": "Χώρες", - "CriticRating": "Βαθμολογία κριτικών", - "DateAdded": "Ημερομηνία προσθήκης", - "DatePlayed": "Ημερομηνία Αναπαραγωγής", - "Days": "Ημέρες", - "Default": "Προεπιλογή", - "DefaultErrorMessage": "Παρουσιάστηκε σφάλμα κατά την επεξεργασία του αιτήματός σας. Παρακαλώ δοκιμάστε ξανά αργότερα.", - "DefaultSubtitlesHelp": "Οι υπότιτλοι φορτώνονται με βάση τις προεπιλεγμένες και αναγκασμένες σημαίες στα ενσωματωμένα μεταδεδομένα. Οι προτιμήσεις γλώσσας εξετάζονται όταν υπάρχουν πολλές επιλογές.", - "Delete": "Διαγραφή", - "DeleteMedia": "Διαγραφή πολυμέσων", - "Depressed": "Μειώθηκε", - "Descending": "Φθίνουσα", - "Desktop": "Επιφάνεια εργασίας", - "DirectPlayError": "Σφάλμα άμεσης αναπαραγωγής", - "DirectPlaying": "Απευθείας Αναπαραγωγή", - "DirectStreamHelp1": "το μέσο είναι συμβατό με τη συσκευή σε σχέση με την ανάλυση και τον τύπο μέσου (H.264, AC3 κ.λπ.), αλλά βρίσκεται σε μη συμβατό περιέκτη αρχείων (.mkv, .avi, .wmv, κ.λπ.). Το βίντεο θα ανασυγκροτηθεί εκ νέου, πριν μεταφερθεί στη συσκευή.", - "DirectStreamHelp2": "Η άμεση ροή ενός αρχείου χρησιμοποιεί ελάχιστη ισχύ επεξεργασίας χωρίς απώλεια της ποιότητας του βίντεο.", - "DirectStreaming": "Απευθείας Αναμετάδοση", - "Director": "Σκηνοθέτης", - "DirectorValue": "Σκηνοθέτης: {0}", - "DirectorsValue": "Σκηνοθέτες: {0}", - "Disc": "Δίσκος", - "Disconnect": "Αποσύνδεση", - "Dislike": "Δεν μου αρέσει", - "Display": "Εμφάνιση", - "DisplayInMyMedia": "Εμφάνιση στην αρχική οθόνη", - "DisplayInOtherHomeScreenSections": "Εμφάνιση στα τμήματα της αρχικής οθόνης, όπως τα πιο πρόσφατα πολυμέσα και συνεχίστε να παρακολουθείτε", - "DisplayMissingEpisodesWithinSeasons": "Εμφάνιση επεισοδίων που λείπουν από την σαιζόν", - "DisplayMissingEpisodesWithinSeasonsHelp": "Αυτό πρέπει επίσης να είναι ενεργοποιημένο για τις βιβλιοθήκες τηλεόρασης στην εγκατάσταση του Jellyfin Server.", - "DisplayModeHelp": "Επιλέξτε τον τύπο οθόνης στον οποίο εκτελείτε το Jellyfin.", - "DoNotRecord": "Μην εγγράψεις", - "Down": "Κάτω", - "Download": "Λήψη", - "DownloadItemLimitHelp": "Προαιρετικό. Ορίστε ένα όριο στον αριθμό των στοιχείων που θα ληφθούν.", - "Downloaded": "Λήφθηκαν", - "Downloading": "Γίνεται Λήψη", - "DownloadingDots": "Λήψη...", - "Downloads": "Λήψεις", - "DownloadsValue": "Λήψεις: {0}", - "DropShadow": "Σκίαση", - "DvrFeatureDescription": "Προγραμματίστε μεμονωμένες εγγραφές Live TV, εγγραφές σειρών και πολλά άλλα με το Jellyfin DVR.", - "DvrSubscriptionRequired": "Το Jellyfin DVR απαιτεί μια ενεργή συνδρομή Jellyfin Premiere.", - "Edit": "Επεξεργασία", - "EditImages": "Επεξεργασία εικόνων", - "EditMetadata": "Επεξεργασία μεταδεδομένων", - "EditSubtitles": "Επεξεργασία υποτίτλων", - "EnableBackdrops": "Ενεργοποίηση Σκηνικών", - "EnableBackdropsHelp": "Αν είναι ενεργοποιημένη, τα backdrops θα εμφανίζονται στο παρασκήνιο ορισμένων σελίδων κατά την περιήγηση στη βιβλιοθήκη", - "EnableCinemaMode": "Ενεργοποιήστε τη λειτουργία Κινηματογράφος", - "EnableColorCodedBackgrounds": "Ενεργοποιήστε τα έγχρωμα κωδικοποιημένα φόντα", - "EnableDisplayMirroring": "Ενεργοποίηση του κατοπτρισμού εμφάνισης", - "EnableExternalVideoPlayers": "Εξωτερικά players για βίντεο", - "EnableExternalVideoPlayersHelp": "Ένα εξωτερικό μενού αναπαραγωγής θα εμφανιστεί κατά την εκκίνηση της αναπαραγωγής βίντεο.", - "EnableNextVideoInfoOverlay": "Ενεργοποιήστε τις επόμενες πληροφορίες βίντεο κατά την αναπαραγωγή", - "EnableNextVideoInfoOverlayHelp": "Στο τέλος ενός βίντεο, εμφανίστε πληροφορίες σχετικά με το επόμενο βίντεο που εμφανίζεται στην τρέχουσα λίστα αναπαραγωγής.", - "EnableThemeSongs": "Ενεργοποίηση Θεματικών Τραγουδιών", - "EnableThemeSongsHelp": "Αν είναι ενεργοποιημένη, τα τραγούδια θεμάτων θα αναπαραχθούν στο παρασκήνιο κατά την περιήγηση στη βιβλιοθήκη.", - "EnableThemeVideos": "Ενεργοποίηση βίντεο θέματος", - "EnableThemeVideosHelp": "Αν είναι ενεργοποιημένη, τα βίντεο θεμάτων θα αναπαραχθούν στο παρασκήνιο κατά την περιήγηση στη βιβλιοθήκη.", - "Ended": "Τέλος", - "EndsAtValue": "Τελειώνει σε {0}", - "Episodes": "Επεισόδια", - "Error": "Σφάλμα", - "ErrorAddingGuestAccount1": "Παρουσιάστηκε ένα σφάλμα κατά την προσθήκη του λογαριασμού Jellyfin Connect. Έχει ο φιλοξενούμενος σας δημιουργήσει έναν λογαριασμό Jellyfin; Μπορούν να εγγραφούν στο {0}.", - "ErrorAddingGuestAccount2": "Εάν εξακολουθείτε να αντιμετωπίζετε κάποιο πρόβλημα, στείλτε ένα μήνυμα ηλεκτρονικού ταχυδρομείου στο {0} και συμπεριλάβετε τη διεύθυνση ηλεκτρονικού ταχυδρομείου σας καθώς και τη δική σας.", - "ErrorAddingJellyfinConnectAccount1": "Παρουσιάστηκε ένα σφάλμα κατά την προσθήκη του λογαριασμού Jellyfin Connect. Έχετε δημιουργήσει έναν λογαριασμό Jellyfin; Εγγραφείτε στο {0}.", - "ErrorAddingJellyfinConnectAccount2": "Αν εξακολουθείτε να αντιμετωπίζετε κάποιο πρόβλημα, στείλτε ένα μήνυμα ηλεκτρονικού ταχυδρομείου στο {0} από τη διεύθυνση ηλεκτρονικού ταχυδρομείου που χρησιμοποιείται με το λογαριασμό Jellyfin.", - "ErrorConnectServerUnreachable": "Παρουσιάστηκε σφάλμα κατά την εκτέλεση της ζητούμενης ενέργειας. Ο διακομιστής σας δεν μπορεί να επικοινωνήσει με το διακομιστή Jellyfin Connect στο {0}. Βεβαιωθείτε ότι ο διακομιστής σας διαθέτει ενεργή σύνδεση στο διαδίκτυο και ότι οι επικοινωνίες επιτρέπονται από οποιοδήποτε τείχος προστασίας ή λογισμικό ασφαλείας που έχετε εγκαταστήσει.", - "ErrorDeletingItem": "Παρουσιάστηκε σφάλμα κατά τη διαγραφή του στοιχείου από τον διακομιστή Jellyfin. Βεβαιωθείτε ότι ο διακομιστής Jellyfin έχει πρόσβαση εγγραφής στο φάκελο πολυμέσων και προσπαθήστε ξανά.", - "ErrorReachingJellyfinConnect": "Παρουσιάστηκε ένα σφάλμα στο διακομιστή Jellyfin Connect. Βεβαιωθείτε ότι έχετε μια ενεργή σύνδεση στο Internet και προσπαθήστε ξανά.", - "ErrorRemovingJellyfinConnectAccount": "Παρουσιάστηκε ένα σφάλμα κατά την κατάργηση του λογαριασμού Jellyfin Connect. Βεβαιωθείτε ότι έχετε μια ενεργή σύνδεση στο Internet και προσπαθήστε ξανά.", - "ExtraLarge": "Πολύ Μεγάλο", - "Extras": "Επιπλέον Υλικό", - "Favorite": "Αγαπημένο", - "Favorites": "Αγαπημένα", - "FeatureRequiresJellyfinPremiere": "Αυτή η δυνατότητα απαιτεί μια ενεργή συνδρομή Jellyfin Premiere.", - "Features": "Χαρακτηριστικά", - "File": "Αρχείο", - "Fill": "Γέμισμα", - "Filters": "Φίλτρα", - "Folders": "Φάκελοι", - "FormatValue": "Φορμάτ: {0}", - "FreeAppsFeatureDescription": "Απολαύστε δωρεάν πρόσβαση σε εφαρμογές Jellyfin για τις συσκευές σας.", - "Friday": "Παρασκευή", - "GenreValue": "Είδος: {0}", - "Genres": "Είδη", - "GenresValue": "Είδη: {0}", - "GroupBySeries": "Ομαδοποίηση κατά σειρά", - "GroupVersions": "Ομαδικές εκδόσεις", - "GuestStar": "Φιλική Συμμετοχή", - "GuestUserNotFound": "Ο χρήστης δεν βρέθηκε. Βεβαιωθείτε ότι το όνομα είναι σωστό και δοκιμάστε ξανά ή δοκιμάστε να εισάγετε τη διεύθυνση ηλεκτρονικού ταχυδρομείου.", - "Guide": "Οδηγός", - "HDPrograms": "Προγράμματα Υψηλής Ανάλυσης", - "HeaderActiveRecordings": "Ενεργές εγγραφές", - "HeaderAddToCollection": "Πρόσθεσε στη Συλλογή", - "HeaderAddToPlaylist": "Πρόσθεσε σε Λίστα", - "HeaderAddUpdateImage": "Προσθήκη / Ενημέρωση εικόνας", - "HeaderAlbumArtists": "Άλμπουμ Καλλιτέχνες", - "HeaderAlreadyPaid": "Ήδη έχετε πληρώσει;", - "HeaderAppearsOn": "Εμφανίζεται σε", - "HeaderAudioBooks": "Μουσικά Βιβλία", - "HeaderAudioSettings": "Ρυθμίσεις Ήχου", - "HeaderBecomeProjectSupporter": "Απόκτησε Συνδρομή Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Οφέλη από την συνδρομή Jellyfin Premiere", - "HeaderCancelRecording": "Ακύρωση Εγγραφής", - "HeaderCancelSeries": "Ακύρωση Σειράς", - "HeaderCinemaMode": "Λειτουργία Κινηματογράφου", - "HeaderCloudSync": "Συγχρονισμός Cloud", - "HeaderConfirmRecordingCancellation": "Επιβεβαιώστε την ακύρωση εγγραφής", - "HeaderContinueListening": "Συνεχίστε την ακρόαση", - "HeaderContinueWatching": "Συνεχίστε την παρακολούθηση", - "HeaderConvertYourRecordings": "Μετατρέψτε τις εγγραφές σας", - "HeaderCustomizeHomeScreen": "Προσαρμογή αρχικής οθόνης", - "HeaderDeleteItem": "Διαγραφή Αντικειμένου", - "HeaderDeleteItems": "Διαγραφή στοιχείων", - "HeaderDisplaySettings": "Ρυθμίσεις Εμφάνισης", - "HeaderDownloadSettings": "Λήψη ρυθμίσεων", - "HeaderEditImages": "Επεξεργασία εικόνων", - "HeaderEnabledFields": "Ενεργά Πεδία", - "HeaderEnabledFieldsHelp": "Καταργήστε την επιλογή ενός πεδίου για να το κλειδώσετε και να αποτρέψετε την αλλαγή των δεδομένων του.", - "HeaderExternalIds": "Εξωτερικά ids:", - "HeaderFavoriteAlbums": "Αγαπημένα Άλμπουμ", - "HeaderFavoriteArtists": "Αγαπημένοι Καλλιτέχνες", - "HeaderFavoriteCollections": "Αγαπημένες Συλλογές", - "HeaderFavoriteEpisodes": "Αγαπημένα Επεισόδια", - "HeaderFavoriteGames": "Αγαπημένα Παιχνίδια", - "HeaderFavoriteMovies": "Αγαπημένες Ταινίες", - "HeaderFavoritePlaylists": "Αγαπημένες Λίστες Αναπαραγωγής", - "HeaderFavoriteShows": "Αγαπημένες Σειρές", - "HeaderFavoriteSongs": "Αγαπημένα Τραγούδια", - "HeaderFavoriteVideos": "Αγαπημένα Βίντεο", - "HeaderFreeApps": "Δωρεάν Εφαρμογές Jellyfin", - "HeaderHomeScreen": "Αρχική οθόνη", - "HeaderIdentifyItemHelp": "Πληκτρολογήστε ένα ή περισσότερα κριτήρια αναζήτησης. Κατάργηση κριτηρίων για την αύξηση των αποτελεσμάτων αναζήτησης.", - "HeaderInvitationSent": "Η πρόσκληση αποστέλλεται", - "HeaderJellyfinAccountAdded": "Λογαριασμός Jellyfin Προστέθηκε", - "HeaderJellyfinAccountRemoved": "Ο λογαριασμός Jellyfin καταργήθηκε", - "HeaderKeepRecording": "Συνέχισε την Εγγραφή", - "HeaderKeepSeries": "Συνέχισε την Σειρά", - "HeaderLatestChannelItems": "Τελευταία στοιχεία καναλιού", - "HeaderLatestChannelMedia": "Τελευταία στοιχεία καναλιού", - "HeaderLatestFrom": "Τελευταία {0}", - "HeaderLatestMedia": "Τελευταία Πολυμέσα", - "HeaderLatestRecordings": "τελευταίες ηχογραφήσεις", - "HeaderLearnMore": "Περισσότερα ", - "HeaderLibraryFolders": "Φάκελος βιβλιοθηκών", - "HeaderLibraryOrder": "Διάταξη Βιβλιοθήκης", - "HeaderMetadataSettings": "Ρυθμίσεις μεταδεδομένων", - "HeaderMusicQuality": "Ποιότητα Μουσικής", - "HeaderMyDevice": "Η Συσκευή μου", - "HeaderMyDownloads": "Οι Λήψεις μου", - "HeaderMyMedia": "Τα Πολυμέσα μου", - "HeaderMyMediaSmall": "Τα Πολυμέσα μου (μικρά)", - "HeaderNewRecording": "Νέα Εγγραφή", - "HeaderNextEpisodePlayingInValue": "Επόμενο επεισόδιο που θα παιχτεί σε {0}", - "HeaderNextUp": "Επόμενο για αναπαραγωγή", - "HeaderNextVideoPlayingInValue": "Επόμενη αναπαραγωγή βίντεο σε {0}", - "HeaderOfflineDownloads": "Πολυμέσα εκτός Σύνδεσης", - "HeaderOfflineDownloadsDescription": "Κάντε λήψη μέσων στις συσκευές σας για εύκολη χρήση εκτός σύνδεσης.", - "HeaderOnNow": "Τώρα", - "HeaderPhotoAlbums": "Άλμπουμ φωτογραφιών", - "HeaderPlayMyMedia": "Αναπαραγωγή των πολυμέσων μου", - "HeaderPlayOn": "Συνέχισε να παίζεις", - "HeaderPlaybackError": "Σφάλμα αναπαραγωγής", - "HeaderRecordingOptions": "Επιλογές Εγγραφής", - "HeaderRemoteControl": "Τηλεχειριστήριο", - "HeaderRestartingJellyfinServer": "Επανεκκίνηση διακομιστή", - "HeaderSaySomethingLike": "Πείτε κάτι σαν...", - "HeaderSecondsValue": "{0} δευτερόλεπτα", - "HeaderSelectDate": "Επιλογή Ημερομηνίας", - "HeaderSeriesOptions": "Επιλογές Σειρών", - "HeaderSeriesStatus": "Κατάσταση Σειράς", - "HeaderSpecialEpisodeInfo": "Ειδικές πληροφορίες επεισοδίου", - "HeaderStartNow": "Ξεκίνα τώρα", - "HeaderStopRecording": "Διακοπή Εγγραφής", - "HeaderSubtitleAppearance": "Εμφάνιση υποτίτλων", - "HeaderSubtitleSettings": "Ρυθμίσεις Υποτίτλων", - "HeaderSyncRequiresSub": "Η λήψη απαιτεί ενεργή συνδρομή Jellyfin Premiere.", - "HeaderTermsOfPurchase": "Όροι αγοράς", - "HeaderTryPlayback": "Δοκιμάστε την αναπαραγωγή", - "HeaderUnlockFeature": "Ξεκλείδωμα χαρακτηριστικών", - "HeaderUploadImage": "Ανεβάστε νέα εικόνα", - "HeaderVideoQuality": "Ποιότητα βίντεο", - "HeaderVideoType": "Τύπος Βίντεο", - "HeaderWaitingForWifi": "Αναμονή για Wifi", - "HeaderWakeServer": "Ενεργοποίηση Server", - "HeaderYouSaid": "Είπατε...", - "Help": "Βοήθεια", - "Hide": "Κρύψε", - "HideWatchedContentFromLatestMedia": "Απόκρυψη προβληθέντων από τα πρόσφατα μέσα", - "Home": "Αρχική", - "Horizontal": "Οριζόντια", - "HowDidYouPay": "Πώς πληρώσατε;", - "IHaveJellyfinPremiere": "Έχω Jellyfin Premiere", - "IPurchasedThisApp": "Αγόρασα αυτήν την εφαρμογή", - "Identify": "Αναγνώριση", - "Images": "Εικόνες", - "ImdbRating": "Βαθμολογία IMDb", - "InstallingPackage": "Εγκατάσταση {0}", - "InstantMix": "Άμεση Mix", - "InterlacedVideoNotSupported": "Δεν είναι υποστηριζόμενο το παρεμβαλλόμενο βίντεο", - "ItemCount": "{0} στοιχεία", - "Items": "Στοιχεία", - "KeepDownload": "Συνέχεια λήψης", - "KeepOnDevice": "Αναπαραγωγή σε αυτή τη συσκευή", - "Kids": "Παιδικά", - "Label3DFormat": "Τρισδιάστατη φόρμα", - "LabelAirDays": "Ημέρες κυκλοφορίας:", - "LabelAirTime": "Ώρα κυκλοφορίας", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Άλμπουμ", - "LabelAlbumArtists": "Άλμπουμ Καλλιτέχνες", - "LabelArtists": "Καλλιτέχνες:", - "LabelArtistsHelp": "Ξεχωρίστε πολλαπλά χρησιμοποιώντας;", - "LabelAudio": "Ήχος:", - "LabelAudioLanguagePreference": "Προτιμώμενη γλώσσα ήχου:", - "LabelBirthDate": "Ημερομηνία Γενεθλίων:", - "LabelBirthYear": "Έτος Γέννησης:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Εγγραφή υπότιτλων:", - "LabelChannels": "Κανάλια:", - "LabelCollection": "Συλλογή:", - "LabelCommunityRating": "Βαθμολογία Κοινότητας:", - "LabelContentType": "Τύπος περιεχομένου:", - "LabelConvertTo": "Μετατροπή σε:", - "LabelCountry": "Χώρα:", - "LabelCriticRating": "Βαθμολογία κριτικών:", - "LabelCustomRating": "Προσαρμοσμένη αξιολόγηση:", - "LabelDashboardTheme": "Θέμα εμφάνισης πίνακα ελέγχου server:", - "LabelDateAdded": "Ημερνία προσθήκης:", - "LabelDateTimeLocale": "Ημερομηνία τοπική ώρα:", - "LabelDeathDate": "Ημερομηνία Θανάτου:", - "LabelDefaultScreen": "Προεπιλεγμένη οθόνη:", - "LabelDiscNumber": "Αριθμός Δίσκου:", - "LabelDisplayLanguage": "Γλώσσα Εμφάνισης", - "LabelDisplayLanguageHelp": "Η μετάφραση του Jellyfin είναι ένα συνεχιζόμενο έργο.", - "LabelDisplayMode": "Λειτουργία προβολής:", - "LabelDisplayOrder": "Σειρά εμφάνισης:", - "LabelDropImageHere": "Κάντε κλικ εδώ, ή κάντε κλικ για να περιηγηθείτε.", - "LabelDropShadow": "Σκίαση:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "Διεύθυνση E-mail", - "LabelEndDate": "Ημερομηνία Λήξης:", - "LabelEpisodeNumber": "Νούμερο Επεισοδίου:", - "LabelFont": "Γραμματοσειρά: ", - "LabelHomeNetworkQuality": "Ποιότητα οικιακού δικτύου:", - "LabelHomeScreenSectionValue": "Αρχική οθόνη {0}:", - "LabelImageType": "Τύπος Εικόνας:", - "LabelInternetQuality": "Ποιότητα Internet:", - "LabelItemLimit": "Όριο στοιχείου:", - "LabelKeep:": "Συνέχισε:", - "LabelKeepUpTo": "Συνεχίστε:", - "LabelLanguage": "Γλώσσα", - "LabelLockItemToPreventChanges": "Κλείδωμα αυτού του στοιχείου για να αποτρέψετε μελλοντικές αλλαγές", - "LabelMaxChromecastBitrate": "Ροή ποιότητας Chromecast:", - "LabelMetadataDownloadLanguage": "Προτιμώμενη γλώσσα εμφάνισης:", - "LabelName": "Όνομα:", - "LabelNumber": "Αριθμός:", - "LabelOriginalAspectRatio": "Αρχικός λόγος διαστάσεων:", - "LabelOriginalTitle": "Αρχικός τίτλος:", - "LabelOverview": "Επισκόπηση:", - "LabelParentNumber": "Αριθμός μητρικής:", - "LabelParentalRating": "Αξιολόγηση γονέων:", - "LabelPath": "Διαδρομή:", - "LabelPersonRole": "Ρόλος:", - "LabelPersonRoleHelp": "Παράδειγμα: οδηγός φορτηγού παγωτού", - "LabelPlaceOfBirth": "Τόπος γέννησης:", - "LabelPlayDefaultAudioTrack": "Αναπαραγωγή προεπιλεγμένου κομματιού ήχου ανεξάρτητα από τη γλώσσα", - "LabelPlaylist": "Λίστα:", - "LabelPreferredSubtitleLanguage": "Προτεινόμενη Γλώσσα υποτίτλων:", - "LabelProfile": "Προφιλ:", - "LabelQuality": "Ποιότητα:", - "LabelReasonForTranscoding": "Λόγος για την Κωδικοποίηση:", - "LabelRecord": "Εγγραφή:", - "LabelRefreshMode": "Τρόπος Ανανέωσης:", - "LabelReleaseDate": "Ημέρα κυκλοφορίας:", - "LabelRuntimeMinutes": "Χρόνος εκτέλεσης (λεπτά):", - "LabelScreensaver": "προφύλαξη οθόνης", - "LabelSeasonNumber": "Αριθμός κύκλου:", - "LabelSelectFolderGroups": "Αυτόματη ομαδοποίηση περιεχομένου από τους ακόλουθους φακέλους σε προβολές όπως ταινίες, μουσική και τηλεόραση:", - "LabelSelectFolderGroupsHelp": "Οι φάκελοι που δεν έχουν επιλεγεί θα εμφανίζονται από μόνοι τους στη δική τους άποψη.", - "LabelShortOverview": "Σύντομη Επισκόπηση", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Παράλειψη πίσω μήκους:", - "LabelSkipForwardLength": "Παράλειψη προς τα εμπρός:", - "LabelSortBy": "Ταξινόμηση κατά:", - "LabelSortOrder": "Σειρά ταξινόμησης:", - "LabelSortTitle": "Σύντομος τίτλος", - "LabelSoundEffects": "Ηχητικά Εφέ", - "LabelSource": "Πηγή:", - "LabelStartWhenPossible": "Έναρξη όταν είναι δυνατό:", - "LabelStatus": "Κατάσταση:", - "LabelStopWhenPossible": "Διακοπή όταν είναι δυνατόν:", - "LabelSubtitlePlaybackMode": "Λειτουργία υποτίτλων:", - "LabelSubtitles": "Υπότιτλοι:", - "LabelSyncJobName": "Όνομα Εργασίας Συγχρονισμού:", - "LabelSyncNoTargetsHelp": "Φαίνεται ότι δεν διαθέτετε επί του παρόντος εφαρμογές που υποστηρίζουν λήψη χωρίς σύνδεση.", - "LabelSyncTo": "Συγχρονισμός σε:", - "LabelTVHomeScreen": "Αρχική οθόνη λειτουργίας τηλεόρασης:", - "LabelTagline": "Ετικέτα:", - "LabelTextBackgroundColor": "Χρώμα φόντου κειμένου:", - "LabelTextColor": "Χρώμα Κειμένου:", - "LabelTextSize": "Μέγεθος Κειμένου:", - "LabelTheme": "Θέμα:", - "LabelTitle": "Τίτλος:", - "LabelTrackNumber": "Αριθμός Κομματιού:", - "LabelType": "Τύπος:", - "LabelVersion": "Έκδοση:", - "LabelVideo": "Βίντεο:", - "LabelWebsite": "Ιστοσελίδα:", - "LabelWindowBackgroundColor": "Χρώμα φόντου κειμένου:", - "LabelYear": "Έτος:", - "Large": "Μεγάλο", - "LatestFromLibrary": "Τελευταία {0}", - "LearnHowYouCanContribute": "Μάθετε πώς μπορείτε να συμβάλλετε.", - "LearnMore": "Περισσότερα ", - "Like": "Μου αρέσει", - "LinksValue": "Σύνδεσμοι: {0}", - "List": "Λίστα", - "Live": "Ζωντανά", - "LiveBroadcasts": "Ζωντανές εκπομπές", - "LiveTV": "ΖΩΝΤΑΝΗ ΤΗΛΕΌΡΑΣΗ", - "LiveTvFeatureDescription": "Κάντε stream ζωντανής τηλεόρασης σε οποιαδήποτε εφαρμογή Jellyfin, με συμβατή συσκευή τηλεοπτικού δέκτη εγκατεστημένη στον διακομιστή σας Jellyfin.", - "LiveTvRequiresUnlock": "Η Ζωντανή Τηλεόραση απαιτεί μία ενεργή συνδρομή στο Jellyfin Premiere.", - "Logo": "λογότυπο", - "ManageRecording": "Διαχείριση Εγγραφών", - "MarkPlayed": "έχει αναπαραχθεί", - "MarkUnplayed": "Δεν αναπαράχθηκε", - "MarkWatched": "Αναπαραχθέντα", - "MediaIsBeingConverted": "Το μέσο μετατρέπεται σε μορφή που είναι συμβατή με τη συσκευή που αναπαράγει τα μέσα.", - "Medium": "Μεσαίο", - "Menu": "Μενού", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Απαιτείται μια ενεργή συνδρομή Jellyfin Premiere για τη δημιουργία αυτοματοποιημένων εγγραφών σε σειρές.", - "MessageAreYouSureDeleteSubtitles": "Είστε σίγουροι ότι θέλετε να διαγράψετε το αρχείο υπότιτλου;", - "MessageConfirmRecordingCancellation": "Είστε σίγουροι ότι θέλετε να ακυρώσετε αυτή την εγγραφή;", - "MessageDownloadQueued": "Η λήψη προγραμματίστηκε.", - "MessageFileReadError": "Παρουσιάστηκε σφάλμα κατά την ανάγνωση του αρχείου. Παρακαλώ προσπάθησε ξανά.", - "MessageIfYouBlockedVoice": "Αν αρνηθήκατε τη φωνητική πρόσβαση στην εφαρμογή, θα χρειαστεί να επαναρυθμίσετε τη ρύθμιση πριν δοκιμάσετε ξανά.", - "MessageInvitationSentToNewUser": "Έγινε αποστολή ενός μηνύματος ηλεκτρονικού ταχυδρομείου στο {0}, καλώντας τα να εγγραφούν στο Jellyfin.", - "MessageInvitationSentToUser": "Ένα μήνυμα ηλεκτρονικού ταχυδρομείου έχει σταλεί στο {0}, καλώντας τα να αποδεχθούν την πρόσκληση κοινής χρήσης.", - "MessageItemSaved": "Το στοιχείο αποθηκεύτηκε", - "MessageItemsAdded": "Τα στοιχεία προστέθηκαν.", - "MessageJellyfinAccontRemoved": "Ο λογαριασμός Jellyfin καταργήθηκε από αυτόν τον χρήστη.", - "MessageJellyfinAccountAdded": "Ο λογαριασμός Jellyfin έχει προστεθεί σε αυτόν τον χρήστη.", - "MessageLeaveEmptyToInherit": "Αφήστε κενό για να κληρονομήσετε τις ρυθμίσεις από ένα γονικό στοιχείο ή την παγκόσμια προεπιλεγμένη τιμή.", - "MessageNoDownloadsFound": "Δεν υπάρχουν λήψεις εκτός σύνδεσης. Κάντε λήψη του μέσου εκτύπωσης για χρήση εκτός σύνδεσης κάνοντας κλικ στην επιλογή Λήψη σε ολόκληρη την εφαρμογή.", - "MessageNoServersAvailableToConnect": "Δεν υπάρχουν διαθέσιμοι διακομιστές για σύνδεση. Αν έχετε προσκληθεί να μοιραστείτε ένα διακομιστή, βεβαιωθείτε ότι το αποδεχθήκατε παρακάτω ή κάνοντας κλικ στο σύνδεσμο του μηνύματος ηλεκτρονικού ταχυδρομείου.", - "MessageNoSyncJobsFound": "Δεν βρέθηκαν λήψεις. Δημιουργήστε εργασίες λήψης χρησιμοποιώντας τα κουμπιά λήψης που βρίσκονται σε ολόκληρη την εφαρμογή.", - "MessagePendingJellyfinAccountAdded": "Ο λογαριασμός Jellyfin έχει προστεθεί σε αυτόν τον χρήστη. Θα σταλεί ένα μήνυμα ηλεκτρονικού ταχυδρομείου στον κάτοχο του λογαριασμού. Η πρόσκληση θα πρέπει να επιβεβαιωθεί κάνοντας κλικ σε ένα σύνδεσμο μέσα στο email.", - "MessagePlayAccessRestricted": "Η αναπαραγωγή αυτού του περιεχομένου είναι αυτή τη στιγμή περιορισμένη. Επικοινωνήστε με τον διαχειριστή του Jellyfin Server για περισσότερες πληροφορίες.", - "MessageToValidateSupporter": "Αν έχετε ενεργή συνδρομή Jellyfin Premiere, βεβαιωθείτε ότι έχετε ρυθμίσει το Jellyfin Premiere στον πίνακα ελέγχου του Jellyfin Server, στον οποίο μπορείτε να έχετε πρόσβαση κάνοντας κλικ στο Jellyfin Premiere στο κύριο μενού.", - "MessageUnlockAppWithPurchaseOrSupporter": "Ξεκλειδώστε αυτό το χαρακτηριστικό καταβάλοντας ένα πολύ μικρό κόστος ή με μία ενεργή συνδρομή στο Jellyfin Premiere.", - "MessageUnlockAppWithSupporter": "Ξεκλειδώστε αυτό το χαρακτηριστικό με μία ενεργή συνδρομή στο Jellyfin Premiere.", - "MessageWeDidntRecognizeCommand": "Λυπούμαστε, δεν αναγνωρίσαμε αυτή την εντολή.", - "MinutesAfter": "λεπτά μετά", - "MinutesBefore": "λεπτά πριν", - "Mobile": "Κινητό/Τάμπλετ", - "Monday": "Δευτέρα", - "More": "Περισσότερα ", - "MoveLeft": "Κινήσου αριστερά", - "MoveRight": "Μετακινήστε δεξιά", - "Movies": "Ταινίες", - "MySubtitles": "Οι Υπότιτλοι μου", - "Name": "Όνομα", - "NewCollection": "Νέα Συλλογή", - "NewCollectionHelp": "Οι συλλογές σάς επιτρέπουν να δημιουργείτε εξατομικευμένες ομαδοποιήσεις ταινιών και άλλου περιεχομένου βιβλιοθήκης.", - "NewCollectionNameExample": "Παράδειγμα: Συλλογή \"Πόλεμος των Άστρων\"", - "NewEpisodes": "Νέα επεισόδια", - "NewEpisodesOnly": "Νέα επεισόδια μόνο", - "News": "Νέα", - "Next": "Επόμενο", - "No": "Οχι", - "NoItemsFound": "Δεν βρέθηκαν στοιχεία.", - "NoSubtitleSearchResultsFound": "δεν βρέθηκαν αποτελέσματα", - "NoSubtitles": "Χωρίς Υπότιτλους", - "NoSubtitlesHelp": "Οι υπότιτλοι δεν θα φορτωθούν από προεπιλογή.Μπορούν ακόμα να ενεργοποιούνται χειροκίνητα κατά την αναπαραγωγή.", - "None": "Κανένα", - "Normal": "Κανονικός", - "Off": "Κλειστό", - "OneChannel": "Ένα κανάλι", - "OnlyForcedSubtitles": "Μόνο αναγκασμένοι υπότιτλοι", - "OnlyForcedSubtitlesHelp": "Μόνο οι υπότιτλοι που έχουν επισημανθεί ως αναγκασμένοι θα φορτωθούν.", - "OnlyImageFormats": "Μόνο μορφές εικόνων (VOBSUB, PGS, SUB / IDX κ.λπ.)", - "Open": "Άνοιγμα", - "OptionNew": "Νέο...", - "Original": "Πρωτότυπο", - "OriginalAirDateValue": "Αρχική ημερομηνία κυκλοφορίας: {0}", - "Overview": "Επισκόπηση", - "PackageInstallCancelled": "Η εγκατάσταση {0} ακυρώθηκε.", - "PackageInstallCompleted": "Η εγκατάσταση {0} ολοκληρώθηκε.", - "PackageInstallFailed": "{0} Αποτυχία", - "ParentalRating": "Καταλληλότητα", - "People": "Άνθρωποι ", - "PerfectMatch": "Τέλεια αντιστοίχιση", - "Photos": "Φωτογραφίες", - "PlaceFavoriteChannelsAtBeginning": "Τοποθετήστε τα αγαπημένα κανάλια στην αρχή", - "Play": "Αναπαραγωγή", - "PlayAllFromHere": "Αναπαραγωγή από εδώ", - "PlayCount": "Καταμέτρηση αναπαραγωγής", - "PlayFromBeginning": "Αναπαραγωγή από την αρχή", - "PlayNext": "Επόμενη Αναπαραγωγή", - "PlayNextEpisodeAutomatically": "Αναπαραγωγή του επόμενου επεισοδίου αυτόματα", - "PlaybackErrorNoCompatibleStream": "Δεν υπάρχουν επί του παρόντος διαθέσιμες συμβατές ροές. Δοκιμάστε ξανά αργότερα ή επικοινωνήστε με τον διαχειριστή του συστήματος για λεπτομέρειες.", - "PlaybackErrorNotAllowed": "Δεν είστε επί του παρόντος εξουσιοδοτημένος να αναπαράγετε αυτό το περιεχόμενο. Επικοινωνήστε με το διαχειριστή του συστήματός σας για λεπτομέρειες.", - "PlaybackErrorPlaceHolder": "Εισαγάγετε τον δίσκο για να παίξετε αυτό το βίντεο.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "Για να ρυθμίσετε τις προεπιλεγμένες ρυθμίσεις αναπαραγωγής, σταματήστε την αναπαραγωγή βίντεο και στη συνέχεια, κάντε κλικ στο εικονίδιο χρήστη στην επάνω δεξιά ενότητα της εφαρμογής.", - "Played": "Έγινε Αναπαραγωγή", - "Playlists": "Λίστες αναπαραγωγής", - "PleaseEnterNameOrId": "Εισαγάγετε ένα όνομα ή ένα εξωτερικό αναγνωριστικό.", - "PleaseRestartServerName": "Κάντε επανεκκίνηση του Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Επιλέξτε μια συσκευή για την οποία θέλετε να κάνετε λήψη.", - "PleaseSelectTwoItems": "Επιλέξτε τουλάχιστον δύο στοιχεία.", - "Premiere": "Πρεμιέρα", - "Premieres": "Πρεμιέρες", - "Previous": "Προηγούμενο", - "Primary": "Πρωτεύον", - "PrivacyPolicy": "Προσωπικά Δεδομένα", - "Producer": "Παραγωγός", - "ProductionLocations": "Τοποθεσίες παραγωγής", - "Programs": "Προγράμματα", - "PromoConvertRecordingsToStreamingFormat": "Αυτόματη μετατροπή των εγγραφών σε φιλική μορφή για streaming με το Jellyfin Premiere. Οι εγγραφές θα μετατραπούν σε μορφή MP4 ή MKV, με βάση τις ρυθμίσεις του διακομιστή Jellyfin.", - "Quality": "Ποιότητα", - "QueueAllFromHere": "Τοποθετήστε στην ουρά αναπαραγωγής όλα από εδώ", - "Raised": "Αυξήθηκε", - "RecentlyWatched": "Πρόσφατα αναπαραχθέντα", - "Record": "Εγγραφή", - "RecordSeries": "Εγγραφή Σειρών", - "RecordingCancelled": "Η εγγραφή ακυρώθηκε.", - "RecordingScheduled": "Η εγγραφή προγραμματίστικε.", - "Recordings": "Εγγραφές", - "RefFramesNotSupported": "Ο αριθμός πλαισίων αναφοράς βίντεο δεν υποστηρίζεται", - "Refresh": "Ανανέωση", - "RefreshDialogHelp": "Τα metadata ανανεώνονται βάσει των ρυθμίσεων και των υπηρεσιών διαδικτύου που είναι ενεργοποιημένες στον πίνακα ελέγχου του Jellyfin Server.", - "RefreshMetadata": "Ανανέωση μεταδεδομένων ", - "RefreshQueued": "Η Ανανέωση προγραμματίστηκε.", - "Reject": "Απόριψη", - "ReleaseDate": "Ημέρα κυκλοφορίας", - "RemoveDownload": "Διέγραψε τη λήψη", - "RemoveFromCollection": "Κατάργηση από την συλλογή", - "RemoveFromPlaylist": "Κατάργηση από την ουρά", - "RemovingFromDevice": "Αφαίρεση από τη συσκευή", - "Repeat": "Επανάληψη", - "RepeatAll": "Επανάληψη όλων", - "RepeatEpisodes": "Επανάληψη επεισοδίων", - "RepeatMode": "Λειτουργία επανάληψης", - "RepeatOne": "Επαναλάβετε ένα", - "ReplaceAllMetadata": "Αντικατάσταση όλων των μεταδεδομένων", - "ReplaceExistingImages": "Αντικατάσταση υπαρχουσών εικόνων", - "RestartPleaseWaitMessage": "Περιμένετε μέχρι ο τερματικός σταθμός Jellyfin να τερματιστεί και να επανεκκινήσει. Αυτό μπορεί να διαρκέσει ένα λεπτό ή δύο.", - "ResumeAt": "Συνέχιση από {0}", - "Retry": "Ξαναδοκιμάσετε", - "RunAtStartup": "Εκτέλεση κατά την εκκίνηση", - "Runtime": "Χρόνος εκτέλεσης", - "Saturday": "Σάββατο", - "Save": "Αποθήκευση", - "ScanForNewAndUpdatedFiles": "Σάρωση για νέα και ενημερωμένα αρχεία", - "Schedule": "Πρόγραμμα", - "Screenshot": "Στιγμιότυπο ", - "Screenshots": "Στιγμιότυπα οθόνης", - "Search": "Αναζήτηση", - "SearchForCollectionInternetMetadata": "Αναζήτηση στο διαδίκτυο για εξώφυλλο και πληροφορίες", - "SearchForMissingMetadata": "Αναζήτηση για ελλειπή μεταδεδομένα", - "SearchForSubtitles": "Αναζήτηση Υποτίτλων", - "SearchResults": "Αποτελέσματα αναζήτησης", - "SecondaryAudioNotSupported": "Η εναλλαγή της γραμμής ήχου δεν υποστηρίζεται", - "SeriesCancelled": "Η Σειρά ακυρώθηκε.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Προγραμματισμός εγγραφών Σειρών", - "SeriesSettings": "Ρυθμίσεις Σειρών", - "SeriesYearToPresent": "{0} - εμφανίστηκε", - "ServerNameIsRestarting": "Ο διακομιστής Jellyfin - {0} επανεκκινείται.", - "ServerNameIsShuttingDown": "Ο διακομιστής Jellyfin - {0} τερματίζεται.", - "ServerUpdateNeeded": "Αυτός ο Jellyfin Server πρέπει να ενημερωθεί. Για να κάνετε λήψη της τελευταίας έκδοσης, επισκεφθείτε την {0}", - "Settings": "Ρυθμίσεις", - "SettingsSaved": "Οι ρυθμίσεις αποθηκεύτηκαν", - "Share": "Κοινή χρήση", - "ShowIndicatorsFor": "Εμφάνιση δεικτών για:", - "ShowTitle": "Εμφάνιση τίτλου", - "ShowYear": "Εμφάνιση έτους", - "Shows": "Σειρές", - "Shuffle": "Ανάμιξη", - "SkipEpisodesAlreadyInMyLibrary": "Μην καταγράφετε επεισόδια που βρίσκονται ήδη στη βιβλιοθήκη μου", - "SkipEpisodesAlreadyInMyLibraryHelp": "Τα επεισόδια θα συγκριθούν με τους αριθμούς κύκλου και επεισοδίων, όταν είναι διαθέσιμοι.", - "Small": "Μικρό", - "SmallCaps": "μικρά γράμματα", - "Smaller": "Μικρότερο", - "Smart": "Έξυπνο", - "SmartSubtitlesHelp": "Οι υπότιτλοι που ταιριάζουν με την προτίμηση γλώσσας θα φορτωθούν όταν ο ήχος είναι σε ξένη γλώσσα.", - "Songs": "Τραγούδια", - "Sort": "Ταξινόμηση", - "SortByValue": "Ταξινόμηση κατά {0}", - "SortChannelsBy": "Στοίχιση καναλιών με:", - "SortName": "Σύντομος τίτλος", - "Sports": "Σπόρ", - "StatsForNerds": "Στατιστικά για κορίτσια", - "StopRecording": "Ακύρωση Εγγραφής", - "Studios": "Στούντιο", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Αυτές οι ρυθμίσεις ισχύουν επίσης για οποιαδήποτε αναπαραγωγή του Chromecast που ξεκίνησε από αυτήν τη συσκευή.", - "SubtitleAppearanceSettingsDisclaimer": "Αυτές οι ρυθμίσεις δεν θα ισχύουν για γραφικούς υποτίτλους (PGS, DVD, κ.λπ.) ή για υπότιτλους που έχουν ενσωματωμένο το δικό τους στυλ (ASS / SSA).", - "SubtitleCodecNotSupported": "Η μορφή υποτίτλων δεν υποστηρίζεται", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "Για να ρυθμίσετε την προεπιλεγμένη εμφάνιση υπότιτλων και τις ρυθμίσεις γλώσσας, σταματήστε την αναπαραγωγή βίντεο και, στη συνέχεια, κάντε κλικ στο εικονίδιο χρήστη στην επάνω δεξιά ενότητα της εφαρμογής.", - "Subtitles": "Υπότιτλοι", - "Suggestions": "Προτάσεις", - "Sunday": "Κυριακή", - "Sync": "Συγχρονισμός", - "SyncJobItemStatusCancelled": "Ακυρώθηκαν", - "SyncJobItemStatusConverting": "Μετατροπή", - "SyncJobItemStatusFailed": "Αποτυχία", - "SyncJobItemStatusQueued": "Στην ουρά", - "SyncJobItemStatusReadyToTransfer": "Έτοιμο για μεταφορά", - "SyncJobItemStatusRemovedFromDevice": "Διαγραφή απο τη συσκευή", - "SyncJobItemStatusSynced": "Λήφθηκαν", - "SyncJobItemStatusSyncedMarkForRemoval": "Αφαίρεση από τη συσκευή", - "SyncJobItemStatusTransferring": "Μεταφορά", - "SyncUnwatchedVideosOnly": "Κάντε λήψη μόνο βίντεο που δεν έχουν αναπαραχθεί", - "SyncUnwatchedVideosOnlyHelp": "Θα πραγματοποιηθούν λήψη μόνο μη αναπαραχθέντων βίντεο και τα βίντεο θα καταργηθούν από τη συσκευή καθώς παρακολουθούνται.", - "SyncingDots": "Συγχρονισμός...", - "TV": "Τηλεόραση", - "Tags": "Ετικέτες", - "TagsValue": "Ετικέτες: {0}", - "TermsOfUse": "Όροι Χρήσης", - "ThankYouForTryingEnjoyOneMinute": "Απολαύστε ένα λεπτό αναπαραγωγής. Σας ευχαριστώ που δοκιμάσατε τον Jellyfin.", - "ThemeSongs": "Θεματικά τραγούδια", - "ThemeVideos": "Θεματικά βίντεο", - "TheseSettingsAffectSubtitlesOnThisDevice": "Αυτές οι ρυθμίσεις επηρεάζουν τους υπότιτλους αυτής της συσκευής", - "Thumb": "Thumb", - "Thursday": "Πέμπτη", - "TrackCount": "{0} κομμάτια", - "Trailer": "Τρέϊλερ", - "Trailers": "Τρέϊλερς", - "Transcoding": "Κωδικοποίηση", - "TryMultiSelect": "Δοκιμάστε την επιλογή πολλαπλών επιλογών", - "TryMultiSelectMessage": "Για να επεξεργαστείτε πολλά στοιχεία πολυμέσων, απλά κάντε κλικ και κρατήστε πατημένο κάθε αφίσα και επιλέξτε τα στοιχεία που θέλετε να διαχειριστείτε. Δοκίμασέ το!", - "Tuesday": "Τρίτη", - "Uniform": "ομοειδής", - "UnlockGuide": "Οδηγός Ξεκλειδώματος", - "Unplayed": "Δεν παίχθηκε", - "Unrated": "Χωρίς Βαθμολογία", - "UntilIDelete": "Μέχρι να το διαγράψω", - "UntilSpaceNeeded": "Μέχρι να χρειαστεί και άλλος χώρος", - "Up": "Επάνω", - "Upload": "Ανεβάστε ", - "ValueAlbumCount": "{0} άλμπουμ", - "ValueDiscNumber": "Δίσκος {0}", - "ValueEpisodeCount": "{0} επεισόδια", - "ValueGameCount": "{0} παιχνίδια", - "ValueMinutes": "{0} λεπτά", - "ValueMovieCount": "{0} ταινίες", - "ValueMusicVideoCount": "{0} μουσικά βίντεο", - "ValueOneAlbum": "1 Άλμπουμ", - "ValueOneEpisode": "1 επεισόδιο", - "ValueOneGame": "1 παιχνίδι", - "ValueOneItem": "1 στοιχείο", - "ValueOneMovie": "1 ταινία", - "ValueOneMusicVideo": "1 μουσικό βίντεο", - "ValueOneSeries": "1 Σειρά", - "ValueOneSong": "1 τραγούδι", - "ValueSeconds": "{0} δευτερόλεπτα", - "ValueSeriesCount": "{0} Σειρές", - "ValueSongCount": "{0} τραγούδια", - "ValueSpecialEpisodeName": "Ειδικά - {0} ", - "Vertical": "Κάθετα", - "VideoBitDepthNotSupported": "Το βάθος του bit βίντεο δεν υποστηρίζεται", - "VideoCodecNotSupported": "Ο κωδικοποιητής βίντεο δεν υποστηρίζεται", - "VideoFramerateNotSupported": "Το βίντεο καρέ δεν υποστηρίζεται", - "VideoLevelNotSupported": "Το επίπεδο βίντεο δεν υποστηρίζεται", - "VideoProfileNotSupported": "Το προφίλ βίντεο δεν υποστηρίζεται", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Η ανάλυση βίντεο δεν υποστηρίζεται", - "ViewAlbum": "Προβολή άλμπουμ", - "ViewArtist": "Εμφάνιση Καλλιτέχνη", - "VoiceInput": "Είσοδος Ήχου", - "WakeServer": "Ενεργοποίηση server", - "WakeServerError": "Τα πακέτα Wake On LAN στάλθηκαν στον server σας, αλλά δεν είναι δυνατή η σύνδεση με τον Jellyfin Server. Το μηχάνημά σας μπορεί να χρειαστεί λίγο περισσότερο χρόνο για να ενεργοποιηθεί, ή ο Jellyfin Server ενδέχεται να μην εκτελείται ενεργά στο μηχάνημα.", - "WakeServerSuccess": "Επιτυχία!", - "Watched": "Έχει γίνει παρακολούθηση", - "Wednesday": "Τετάρτη", - "WifiRequiredToDownload": "Απαιτείται σύνδεση Wi-Fi για να συνεχίσετε τη λήψη.", - "Writer": "Συγγραφέας", - "Yes": "Ναι" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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": "\u0391\u03bd \u03ad\u03c7\u03b5\u03c4\u03b5 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae Emby Premiere, \u03b2\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9 \u03c4\u03bf Emby Premiere \u03c3\u03c4\u03bf\u03bd \u03c0\u03af\u03bd\u03b1\u03ba\u03b1 \u03b5\u03bb\u03ad\u03b3\u03c7\u03bf\u03c5 \u03c4\u03bf\u03c5 Emby Server, \u03c3\u03c4\u03bf\u03bd \u03bf\u03c0\u03bf\u03af\u03bf \u03bc\u03c0\u03bf\u03c1\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03ba\u03ac\u03bd\u03bf\u03bd\u03c4\u03b1\u03c2 \u03ba\u03bb\u03b9\u03ba \u03c3\u03c4\u03bf Emby Premiere \u03c3\u03c4\u03bf \u03ba\u03cd\u03c1\u03b9\u03bf \u03bc\u03b5\u03bd\u03bf\u03cd.", + "ValueSpecialEpisodeName": "\u0395\u03b9\u03b4\u03b9\u03ba\u03ac - {0} ", + "Share": "\u039a\u03bf\u03b9\u03bd\u03ae \u03c7\u03c1\u03ae\u03c3\u03b7", + "Add": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7", + "ServerUpdateNeeded": "\u0391\u03c5\u03c4\u03cc\u03c2 \u03bf Emby Server \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03b5\u03bd\u03b7\u03bc\u03b5\u03c1\u03c9\u03b8\u03b5\u03af. \u0393\u03b9\u03b1 \u03bd\u03b1 \u03ba\u03ac\u03bd\u03b5\u03c4\u03b5 \u03bb\u03ae\u03c8\u03b7 \u03c4\u03b7\u03c2 \u03c4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1\u03c2 \u03ad\u03ba\u03b4\u03bf\u03c3\u03b7\u03c2, \u03b5\u03c0\u03b9\u03c3\u03ba\u03b5\u03c6\u03b8\u03b5\u03af\u03c4\u03b5 \u03c4\u03b7\u03bd {0}", + "LiveTvRequiresUnlock": "\u0397 \u0396\u03c9\u03bd\u03c4\u03b1\u03bd\u03ae \u03a4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7 \u03b1\u03c0\u03b1\u03b9\u03c4\u03b5\u03af \u03bc\u03af\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae \u03c3\u03c4\u03bf Emby Premiere.", + "AttributeNew": "\u039d\u03ad\u03bf", + "Premiere": "\u03a0\u03c1\u03b5\u03bc\u03b9\u03ad\u03c1\u03b1", + "Live": "\u0396\u03c9\u03bd\u03c4\u03b1\u03bd\u03ac", + "Repeat": "\u0395\u03c0\u03b1\u03bd\u03ac\u03bb\u03b7\u03c8\u03b7", + "TrackCount": "{0} \u03ba\u03bf\u03bc\u03bc\u03ac\u03c4\u03b9\u03b1", + "ItemCount": "{0} \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1", + "OriginalAirDateValue": "\u0391\u03c1\u03c7\u03b9\u03ba\u03ae \u03b7\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u03ba\u03c5\u03ba\u03bb\u03bf\u03c6\u03bf\u03c1\u03af\u03b1\u03c2: {0}", + "EndsAtValue": "\u03a4\u03b5\u03bb\u03b5\u03b9\u03ce\u03bd\u03b5\u03b9 \u03c3\u03b5 {0}", + "HeaderSelectDate": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1\u03c2", + "Watched": "\u0388\u03c7\u03b5\u03b9 \u03b3\u03af\u03bd\u03b5\u03b9 \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03cd\u03b8\u03b7\u03c3\u03b7", + "AirDate": "\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u03c0\u03c1\u03bf\u03b2\u03bf\u03bb\u03ae\u03c2", + "Played": "\u0388\u03b3\u03b9\u03bd\u03b5 \u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae", + "ButtonOk": "Ok", + "ButtonCancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 ", + "AccessRestrictedTryAgainLater": "\u0397 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03c0\u03af \u03c4\u03bf\u03c5 \u03c0\u03b1\u03c1\u03cc\u03bd\u03c4\u03bf\u03c2 \u03c0\u03b5\u03c1\u03b9\u03bf\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03b7. \u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03b4\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03c4\u03b5 \u03be\u03b1\u03bd\u03ac \u03b1\u03c1\u03b3\u03cc\u03c4\u03b5\u03c1\u03b1.", + "ButtonGotIt": "\u03a4\u03bf \u03ba\u03b1\u03c4\u03ac\u03bb\u03b1\u03b2\u03b1", + "ButtonRestart": "\u0395\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7", + "RecordingCancelled": "\u0397 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae \u03b1\u03ba\u03c5\u03c1\u03ce\u03b8\u03b7\u03ba\u03b5.", + "SeriesCancelled": "\u0397 \u03a3\u03b5\u03b9\u03c1\u03ac \u03b1\u03ba\u03c5\u03c1\u03ce\u03b8\u03b7\u03ba\u03b5.", + "RecordingScheduled": "\u0397 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae \u03c0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03af\u03c3\u03c4\u03b9\u03ba\u03b5.", + "SeriesRecordingScheduled": "\u03a0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03cc\u03c2 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ce\u03bd \u03a3\u03b5\u03b9\u03c1\u03ce\u03bd", + "HeaderNewRecording": "\u039d\u03ad\u03b1 \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae", + "WakeServer": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 server", + "HeaderWakeServer": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 Server", + "AttemptingWakeServer": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 server \u03c3\u03b5 \u03b5\u03be\u03ad\u03bb\u03b9\u03be\u03b7. \u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03c0\u03b5\u03c1\u03b9\u03bc\u03ad\u03bd\u03b5\u03c4\u03b5...", + "WakeServerSuccess": "\u0395\u03c0\u03b9\u03c4\u03c5\u03c7\u03af\u03b1!", + "HeaderCustomizeHomeScreen": "\u03a0\u03c1\u03bf\u03c3\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae \u03b1\u03c1\u03c7\u03b9\u03ba\u03ae\u03c2 \u03bf\u03b8\u03cc\u03bd\u03b7\u03c2", + "WakeServerError": "\u03a4\u03b1 \u03c0\u03b1\u03ba\u03ad\u03c4\u03b1 Wake On LAN \u03c3\u03c4\u03ac\u03bb\u03b8\u03b7\u03ba\u03b1\u03bd \u03c3\u03c4\u03bf\u03bd server \u03c3\u03b1\u03c2, \u03b1\u03bb\u03bb\u03ac \u03b4\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae \u03b7 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7 \u03bc\u03b5 \u03c4\u03bf\u03bd Emby Server. \u03a4\u03bf \u03bc\u03b7\u03c7\u03ac\u03bd\u03b7\u03bc\u03ac \u03c3\u03b1\u03c2 \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03c7\u03c1\u03b5\u03b9\u03b1\u03c3\u03c4\u03b5\u03af \u03bb\u03af\u03b3\u03bf \u03c0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03bf \u03c7\u03c1\u03cc\u03bd\u03bf \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03b8\u03b5\u03af, \u03ae \u03bf Emby Server \u03b5\u03bd\u03b4\u03ad\u03c7\u03b5\u03c4\u03b1\u03b9 \u03bd\u03b1 \u03bc\u03b7\u03bd \u03b5\u03ba\u03c4\u03b5\u03bb\u03b5\u03af\u03c4\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ac \u03c3\u03c4\u03bf \u03bc\u03b7\u03c7\u03ac\u03bd\u03b7\u03bc\u03b1.", + "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", + "SortByValue": "\u03a4\u03b1\u03be\u03b9\u03bd\u03cc\u03bc\u03b7\u03c3\u03b7 \u03ba\u03b1\u03c4\u03ac {0}", + "LabelSortBy": "\u03a4\u03b1\u03be\u03b9\u03bd\u03cc\u03bc\u03b7\u03c3\u03b7 \u03ba\u03b1\u03c4\u03ac:", + "LabelSortOrder": "\u03a3\u03b5\u03b9\u03c1\u03ac \u03c4\u03b1\u03be\u03b9\u03bd\u03cc\u03bc\u03b7\u03c3\u03b7\u03c2:", + "HeaderPhotoAlbums": "\u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc \u03c6\u03c9\u03c4\u03bf\u03b3\u03c1\u03b1\u03c6\u03b9\u03ce\u03bd", + "Photos": "\u03a6\u03c9\u03c4\u03bf\u03b3\u03c1\u03b1\u03c6\u03af\u03b5\u03c2", + "HeaderAppearsOn": "\u0395\u03bc\u03c6\u03b1\u03bd\u03af\u03b6\u03b5\u03c4\u03b1\u03b9 \u03c3\u03b5", + "List": "\u039b\u03af\u03c3\u03c4\u03b1", + "RecordSeries": "\u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae \u03a3\u03b5\u03b9\u03c1\u03ce\u03bd", + "HeaderCinemaMode": "\u039b\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u039a\u03b9\u03bd\u03b7\u03bc\u03b1\u03c4\u03bf\u03b3\u03c1\u03ac\u03c6\u03bf\u03c5", + "HeaderCloudSync": "\u03a3\u03c5\u03b3\u03c7\u03c1\u03bf\u03bd\u03b9\u03c3\u03bc\u03cc\u03c2 Cloud", + "Downloads": "\u039b\u03ae\u03c8\u03b5\u03b9\u03c2", + "HeaderMyDownloads": "\u039f\u03b9 \u039b\u03ae\u03c8\u03b5\u03b9\u03c2 \u03bc\u03bf\u03c5", + "HeaderOfflineDownloads": "\u03a0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03b1 \u03b5\u03ba\u03c4\u03cc\u03c2 \u03a3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2", + "HeaderOfflineDownloadsDescription": "\u039a\u03ac\u03bd\u03c4\u03b5 \u03bb\u03ae\u03c8\u03b7 \u03bc\u03ad\u03c3\u03c9\u03bd \u03c3\u03c4\u03b9\u03c2 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ad\u03c2 \u03c3\u03b1\u03c2 \u03b3\u03b9\u03b1 \u03b5\u03cd\u03ba\u03bf\u03bb\u03b7 \u03c7\u03c1\u03ae\u03c3\u03b7 \u03b5\u03ba\u03c4\u03cc\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2.", + "CloudSyncFeatureDescription": "\u03a3\u03c5\u03b3\u03c7\u03c1\u03bf\u03bd\u03af\u03c3\u03c4\u03b5 \u03c4\u03b1 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03b1 \u03c3\u03b1\u03c2 \u03c3\u03c4\u03bf cloud \u03b3\u03b9\u03b1 \u03b5\u03cd\u03ba\u03bf\u03bb\u03b7 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03b1\u03bd\u03c4\u03b9\u03b3\u03c1\u03ac\u03c6\u03c9\u03bd \u03b1\u03c3\u03c6\u03b1\u03bb\u03b5\u03af\u03b1\u03c2, \u03b1\u03c1\u03c7\u03b5\u03b9\u03bf\u03b8\u03ad\u03c4\u03b7\u03c3\u03b7 \u03ba\u03b1\u03b9 \u03bc\u03b5\u03c4\u03b1\u03c4\u03c1\u03bf\u03c0\u03ae.", + "LiveTvFeatureDescription": "\u039a\u03ac\u03bd\u03c4\u03b5 stream \u03b6\u03c9\u03bd\u03c4\u03b1\u03bd\u03ae\u03c2 \u03c4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7\u03c2 \u03c3\u03b5 \u03bf\u03c0\u03bf\u03b9\u03b1\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae Emby, \u03bc\u03b5 \u03c3\u03c5\u03bc\u03b2\u03b1\u03c4\u03ae \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03c4\u03b7\u03bb\u03b5\u03bf\u03c0\u03c4\u03b9\u03ba\u03bf\u03cd \u03b4\u03ad\u03ba\u03c4\u03b7 \u03b5\u03b3\u03ba\u03b1\u03c4\u03b5\u03c3\u03c4\u03b7\u03bc\u03ad\u03bd\u03b7 \u03c3\u03c4\u03bf\u03bd \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae \u03c3\u03b1\u03c2 Emby.", + "DvrFeatureDescription": "\u03a0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03af\u03c3\u03c4\u03b5 \u03bc\u03b5\u03bc\u03bf\u03bd\u03c9\u03bc\u03ad\u03bd\u03b5\u03c2 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ad\u03c2 Live TV, \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ad\u03c2 \u03c3\u03b5\u03b9\u03c1\u03ce\u03bd \u03ba\u03b1\u03b9 \u03c0\u03bf\u03bb\u03bb\u03ac \u03ac\u03bb\u03bb\u03b1 \u03bc\u03b5 \u03c4\u03bf Emby DVR.", + "CinemaModeFeatureDescription": "\u0397 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u039a\u03b9\u03bd\u03b7\u03bc\u03b1\u03c4\u03bf\u03b3\u03c1\u03ac\u03c6\u03bf\u03c5 \u03c3\u03ac\u03c2 \u03c0\u03c1\u03bf\u03c3\u03c6\u03ad\u03c1\u03b5\u03b9 \u03c4\u03b7\u03bd \u03c0\u03c1\u03b1\u03b3\u03bc\u03b1\u03c4\u03b9\u03ba\u03ae \u03ba\u03b9\u03bd\u03b7\u03bc\u03b1\u03c4\u03bf\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03ae \u03b5\u03bc\u03c0\u03b5\u03b9\u03c1\u03af\u03b1 \u03bc\u03b5 \u03c1\u03c5\u03bc\u03bf\u03c5\u03bb\u03ba\u03bf\u03cd\u03bc\u03b5\u03bd\u03b1 \u03ba\u03b1\u03b9 \u03c0\u03c1\u03bf\u03c3\u03b1\u03c1\u03bc\u03bf\u03c3\u03bc\u03ad\u03bd\u03b5\u03c2 intros \u03c0\u03c1\u03b9\u03bd \u03b1\u03c0\u03cc \u03c4\u03b7 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1.", + "HeaderFreeApps": "\u0394\u03c9\u03c1\u03b5\u03ac\u03bd \u0395\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ad\u03c2 Emby", + "FreeAppsFeatureDescription": "\u0391\u03c0\u03bf\u03bb\u03b1\u03cd\u03c3\u03c4\u03b5 \u03b4\u03c9\u03c1\u03b5\u03ac\u03bd \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03b5 \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ad\u03c2 Emby \u03b3\u03b9\u03b1 \u03c4\u03b9\u03c2 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ad\u03c2 \u03c3\u03b1\u03c2.", + "HeaderBecomeProjectSupporter": "\u0391\u03c0\u03cc\u03ba\u03c4\u03b7\u03c3\u03b5 \u03a3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "\u0391\u03c0\u03b1\u03b9\u03c4\u03b5\u03af\u03c4\u03b1\u03b9 \u03bc\u03b9\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae Emby Premiere \u03b3\u03b9\u03b1 \u03c4\u03b7 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03b1\u03c5\u03c4\u03bf\u03bc\u03b1\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03c9\u03bd \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ce\u03bd \u03c3\u03b5 \u03c3\u03b5\u03b9\u03c1\u03ad\u03c2.", + "LabelEmailAddress": "\u0394\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 E-mail", + "PromoConvertRecordingsToStreamingFormat": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b7 \u03bc\u03b5\u03c4\u03b1\u03c4\u03c1\u03bf\u03c0\u03ae \u03c4\u03c9\u03bd \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ce\u03bd \u03c3\u03b5 \u03c6\u03b9\u03bb\u03b9\u03ba\u03ae \u03bc\u03bf\u03c1\u03c6\u03ae \u03b3\u03b9\u03b1 streaming \u03bc\u03b5 \u03c4\u03bf Emby Premiere. \u039f\u03b9 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ad\u03c2 \u03b8\u03b1 \u03bc\u03b5\u03c4\u03b1\u03c4\u03c1\u03b1\u03c0\u03bf\u03cd\u03bd \u03c3\u03b5 \u03bc\u03bf\u03c1\u03c6\u03ae MP4 \u03ae MKV, \u03bc\u03b5 \u03b2\u03ac\u03c3\u03b7 \u03c4\u03b9\u03c2 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03c4\u03bf\u03c5 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae Emby.", + "FeatureRequiresEmbyPremiere": "\u0391\u03c5\u03c4\u03ae \u03b7 \u03b4\u03c5\u03bd\u03b1\u03c4\u03cc\u03c4\u03b7\u03c4\u03b1 \u03b1\u03c0\u03b1\u03b9\u03c4\u03b5\u03af \u03bc\u03b9\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae Emby Premiere.", + "HeaderConvertYourRecordings": "\u039c\u03b5\u03c4\u03b1\u03c4\u03c1\u03ad\u03c8\u03c4\u03b5 \u03c4\u03b9\u03c2 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ad\u03c2 \u03c3\u03b1\u03c2", + "Record": "\u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae", + "Save": "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7", + "Edit": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1", + "Download": "\u039b\u03ae\u03c8\u03b7", + "Downloaded": "\u039b\u03ae\u03c6\u03b8\u03b7\u03ba\u03b1\u03bd", + "Downloading": "\u0393\u03af\u03bd\u03b5\u03c4\u03b1\u03b9 \u039b\u03ae\u03c8\u03b7", + "Advanced": "\u0393\u03b9\u03b1 \u03c0\u03c1\u03bf\u03c7\u03c9\u03c1\u03b7\u03bc\u03ad\u03bd\u03bf\u03c5\u03c2", + "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": "\u0397 \u03b4\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03b1\u03c5\u03c4\u03bf\u03cd \u03c4\u03bf\u03c5 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf\u03c5 \u03b8\u03b1 \u03c4\u03bf \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03b9 \u03c4\u03cc\u03c3\u03bf \u03b1\u03c0\u03cc \u03c4\u03bf \u03c3\u03cd\u03c3\u03c4\u03b7\u03bc\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd \u03cc\u03c3\u03bf \u03ba\u03b1\u03b9 \u03b1\u03c0\u03cc \u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd \u03c3\u03b1\u03c2. \u0395\u03af\u03c3\u03c4\u03b5 \u03b2\u03ad\u03b2\u03b1\u03b9\u03bf\u03b9 \u03cc\u03c4\u03b9 \u03b8\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03c3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03b5\u03c4\u03b5;", + "Refresh": "\u0391\u03bd\u03b1\u03bd\u03ad\u03c9\u03c3\u03b7", + "RefreshQueued": "\u0397 \u0391\u03bd\u03b1\u03bd\u03ad\u03c9\u03c3\u03b7 \u03c0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03af\u03c3\u03c4\u03b7\u03ba\u03b5.", + "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": "\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", + "LabelDisplayMode": "\u039b\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03c0\u03c1\u03bf\u03b2\u03bf\u03bb\u03ae\u03c2:", + "Desktop": "\u0395\u03c0\u03b9\u03c6\u03ac\u03bd\u03b5\u03b9\u03b1 \u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1\u03c2", + "Mobile": "\u039a\u03b9\u03bd\u03b7\u03c4\u03cc\/\u03a4\u03ac\u03bc\u03c0\u03bb\u03b5\u03c4", + "TV": "\u03a4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7", + "DisplayModeHelp": "\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03c4\u03bf\u03bd \u03c4\u03cd\u03c0\u03bf \u03bf\u03b8\u03cc\u03bd\u03b7\u03c2 \u03c3\u03c4\u03bf\u03bd \u03bf\u03c0\u03bf\u03af\u03bf \u03b5\u03ba\u03c4\u03b5\u03bb\u03b5\u03af\u03c4\u03b5 \u03c4\u03bf Emby.", + "LabelDisplayLanguage": "\u0393\u03bb\u03ce\u03c3\u03c3\u03b1 \u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7\u03c2", + "LabelDisplayLanguageHelp": "\u0397 \u03bc\u03b5\u03c4\u03ac\u03c6\u03c1\u03b1\u03c3\u03b7 \u03c4\u03bf\u03c5 Emby \u03b5\u03af\u03bd\u03b1\u03b9 \u03ad\u03bd\u03b1 \u03c3\u03c5\u03bd\u03b5\u03c7\u03b9\u03b6\u03cc\u03bc\u03b5\u03bd\u03bf \u03ad\u03c1\u03b3\u03bf.", + "LearnHowYouCanContribute": "\u039c\u03ac\u03b8\u03b5\u03c4\u03b5 \u03c0\u03ce\u03c2 \u03bc\u03c0\u03bf\u03c1\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03c3\u03c5\u03bc\u03b2\u03ac\u03bb\u03bb\u03b5\u03c4\u03b5.", + "NewCollectionHelp": "\u039f\u03b9 \u03c3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ad\u03c2 \u03c3\u03ac\u03c2 \u03b5\u03c0\u03b9\u03c4\u03c1\u03ad\u03c0\u03bf\u03c5\u03bd \u03bd\u03b1 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03b5\u03af\u03c4\u03b5 \u03b5\u03be\u03b1\u03c4\u03bf\u03bc\u03b9\u03ba\u03b5\u03c5\u03bc\u03ad\u03bd\u03b5\u03c2 \u03bf\u03bc\u03b1\u03b4\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03b9\u03c2 \u03c4\u03b1\u03b9\u03bd\u03b9\u03ce\u03bd \u03ba\u03b1\u03b9 \u03ac\u03bb\u03bb\u03bf\u03c5 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7\u03c2.", + "SearchForCollectionInternetMetadata": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03c3\u03c4\u03bf \u03b4\u03b9\u03b1\u03b4\u03af\u03ba\u03c4\u03c5\u03bf \u03b3\u03b9\u03b1 \u03b5\u03be\u03ce\u03c6\u03c5\u03bb\u03bb\u03bf \u03ba\u03b1\u03b9 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2", + "DisplayMissingEpisodesWithinSeasons": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03b5\u03c0\u03b5\u03b9\u03c3\u03bf\u03b4\u03af\u03c9\u03bd \u03c0\u03bf\u03c5 \u03bb\u03b5\u03af\u03c0\u03bf\u03c5\u03bd \u03b1\u03c0\u03cc \u03c4\u03b7\u03bd \u03c3\u03b1\u03b9\u03b6\u03cc\u03bd", + "DisplayMissingEpisodesWithinSeasonsHelp": "\u0391\u03c5\u03c4\u03cc \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03b5\u03c0\u03af\u03c3\u03b7\u03c2 \u03bd\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf \u03b3\u03b9\u03b1 \u03c4\u03b9\u03c2 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b5\u03c2 \u03c4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7\u03c2 \u03c3\u03c4\u03b7\u03bd \u03b5\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03bf\u03c5 Emby Server.", + "EnableThemeSongs": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u0398\u03b5\u03bc\u03b1\u03c4\u03b9\u03ba\u03ce\u03bd \u03a4\u03c1\u03b1\u03b3\u03bf\u03c5\u03b4\u03b9\u03ce\u03bd", + "EnableBackdrops": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03a3\u03ba\u03b7\u03bd\u03b9\u03ba\u03ce\u03bd", + "EnableThemeSongsHelp": "\u0391\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03c4\u03b1 \u03c4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1 \u03b8\u03b5\u03bc\u03ac\u03c4\u03c9\u03bd \u03b8\u03b1 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03c7\u03b8\u03bf\u03cd\u03bd \u03c3\u03c4\u03bf \u03c0\u03b1\u03c1\u03b1\u03c3\u03ba\u03ae\u03bd\u03b9\u03bf \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03c0\u03b5\u03c1\u03b9\u03ae\u03b3\u03b7\u03c3\u03b7 \u03c3\u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7.", + "EnableBackdropsHelp": "\u0391\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03c4\u03b1 backdrops \u03b8\u03b1 \u03b5\u03bc\u03c6\u03b1\u03bd\u03af\u03b6\u03bf\u03bd\u03c4\u03b1\u03b9 \u03c3\u03c4\u03bf \u03c0\u03b1\u03c1\u03b1\u03c3\u03ba\u03ae\u03bd\u03b9\u03bf \u03bf\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03c9\u03bd \u03c3\u03b5\u03bb\u03af\u03b4\u03c9\u03bd \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03c0\u03b5\u03c1\u03b9\u03ae\u03b3\u03b7\u03c3\u03b7 \u03c3\u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7", + "EnableThemeVideos": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b8\u03ad\u03bc\u03b1\u03c4\u03bf\u03c2", + "EnableThemeVideosHelp": "\u0391\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03c4\u03b1 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b8\u03b5\u03bc\u03ac\u03c4\u03c9\u03bd \u03b8\u03b1 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03c7\u03b8\u03bf\u03cd\u03bd \u03c3\u03c4\u03bf \u03c0\u03b1\u03c1\u03b1\u03c3\u03ba\u03ae\u03bd\u03b9\u03bf \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03c0\u03b5\u03c1\u03b9\u03ae\u03b3\u03b7\u03c3\u03b7 \u03c3\u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7.", + "RunAtStartup": "\u0395\u03ba\u03c4\u03ad\u03bb\u03b5\u03c3\u03b7 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7", + "LabelScreensaver": "\u03c0\u03c1\u03bf\u03c6\u03cd\u03bb\u03b1\u03be\u03b7 \u03bf\u03b8\u03cc\u03bd\u03b7\u03c2", + "LabelSoundEffects": "\u0397\u03c7\u03b7\u03c4\u03b9\u03ba\u03ac \u0395\u03c6\u03ad", + "LabelSkin": "Skin:", + "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": "\u03a4\u03b1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03c0\u03c1\u03bf\u03c3\u03c4\u03ad\u03b8\u03b7\u03ba\u03b1\u03bd.", + "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", + "LabelTheme": "\u0398\u03ad\u03bc\u03b1:", + "LabelDashboardTheme": "\u0398\u03ad\u03bc\u03b1 \u03b5\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7\u03c2 \u03c0\u03af\u03bd\u03b1\u03ba\u03b1 \u03b5\u03bb\u03ad\u03b3\u03c7\u03bf\u03c5 server:", + "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": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7", + "NoSubtitleSearchResultsFound": "\u03b4\u03b5\u03bd \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b1\u03bd \u03b1\u03c0\u03bf\u03c4\u03b5\u03bb\u03ad\u03c3\u03bc\u03b1\u03c4\u03b1", + "File": "\u0391\u03c1\u03c7\u03b5\u03af\u03bf", + "MessageAreYouSureDeleteSubtitles": "\u0395\u03af\u03c3\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03bf\u03b9 \u03cc\u03c4\u03b9 \u03b8\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03c4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03c5;", + "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": "\u0397 \u03bb\u03ae\u03c8\u03b7 \u03c0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03af\u03c3\u03c4\u03b7\u03ba\u03b5.", + "EditSubtitles": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03c5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd", + "UnlockGuide": "\u039f\u03b4\u03b7\u03b3\u03cc\u03c2 \u039e\u03b5\u03ba\u03bb\u03b5\u03b9\u03b4\u03ce\u03bc\u03b1\u03c4\u03bf\u03c2", + "RefreshMetadata": "\u0391\u03bd\u03b1\u03bd\u03ad\u03c9\u03c3\u03b7 \u03bc\u03b5\u03c4\u03b1\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd ", + "ReplaceExistingImages": "\u0391\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c5\u03c0\u03b1\u03c1\u03c7\u03bf\u03c5\u03c3\u03ce\u03bd \u03b5\u03b9\u03ba\u03cc\u03bd\u03c9\u03bd", + "ReplaceAllMetadata": "\u0391\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03cc\u03bb\u03c9\u03bd \u03c4\u03c9\u03bd \u03bc\u03b5\u03c4\u03b1\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd", + "SearchForMissingMetadata": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03b3\u03b9\u03b1 \u03b5\u03bb\u03bb\u03b5\u03b9\u03c0\u03ae \u03bc\u03b5\u03c4\u03b1\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03b1", + "LabelRefreshMode": "\u03a4\u03c1\u03cc\u03c0\u03bf\u03c2 \u0391\u03bd\u03b1\u03bd\u03ad\u03c9\u03c3\u03b7\u03c2:", + "NoItemsFound": "\u0394\u03b5\u03bd \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b1\u03bd \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1.", + "HeaderSaySomethingLike": "\u03a0\u03b5\u03af\u03c4\u03b5 \u03ba\u03ac\u03c4\u03b9 \u03c3\u03b1\u03bd...", + "ButtonTryAgain": "\u03a0\u03c1\u03bf\u03c3\u03c0\u03b1\u03b8\u03ae\u03c3\u03c4\u03b5 \u03be\u03b1\u03bd\u03ac", + "HeaderYouSaid": "\u0395\u03af\u03c0\u03b1\u03c4\u03b5...", + "MessageWeDidntRecognizeCommand": "\u039b\u03c5\u03c0\u03bf\u03cd\u03bc\u03b1\u03c3\u03c4\u03b5, \u03b4\u03b5\u03bd \u03b1\u03bd\u03b1\u03b3\u03bd\u03c9\u03c1\u03af\u03c3\u03b1\u03bc\u03b5 \u03b1\u03c5\u03c4\u03ae \u03c4\u03b7\u03bd \u03b5\u03bd\u03c4\u03bf\u03bb\u03ae.", + "MessageIfYouBlockedVoice": "\u0391\u03bd \u03b1\u03c1\u03bd\u03b7\u03b8\u03ae\u03ba\u03b1\u03c4\u03b5 \u03c4\u03b7 \u03c6\u03c9\u03bd\u03b7\u03c4\u03b9\u03ba\u03ae \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03c4\u03b7\u03bd \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae, \u03b8\u03b1 \u03c7\u03c1\u03b5\u03b9\u03b1\u03c3\u03c4\u03b5\u03af \u03bd\u03b1 \u03b5\u03c0\u03b1\u03bd\u03b1\u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b7 \u03c1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7 \u03c0\u03c1\u03b9\u03bd \u03b4\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03b5\u03c4\u03b5 \u03be\u03b1\u03bd\u03ac.", + "ValueDiscNumber": "\u0394\u03af\u03c3\u03ba\u03bf\u03c2 {0}", + "Unrated": "\u03a7\u03c9\u03c1\u03af\u03c2 \u0392\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1", + "Favorite": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03bf", + "Like": "\u039c\u03bf\u03c5 \u03b1\u03c1\u03ad\u03c3\u03b5\u03b9", + "Dislike": "\u0394\u03b5\u03bd \u03bc\u03bf\u03c5 \u03b1\u03c1\u03ad\u03c3\u03b5\u03b9", + "RefreshDialogHelp": "\u03a4\u03b1 metadata \u03b1\u03bd\u03b1\u03bd\u03b5\u03ce\u03bd\u03bf\u03bd\u03c4\u03b1\u03b9 \u03b2\u03ac\u03c3\u03b5\u03b9 \u03c4\u03c9\u03bd \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c9\u03bd \u03ba\u03b1\u03b9 \u03c4\u03c9\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03b9\u03ce\u03bd \u03b4\u03b9\u03b1\u03b4\u03b9\u03ba\u03c4\u03cd\u03bf\u03c5 \u03c0\u03bf\u03c5 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b5\u03c2 \u03c3\u03c4\u03bf\u03bd \u03c0\u03af\u03bd\u03b1\u03ba\u03b1 \u03b5\u03bb\u03ad\u03b3\u03c7\u03bf\u03c5 \u03c4\u03bf\u03c5 Emby Server.", + "Open": "\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1", + "Play": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae", + "AddToPlayQueue": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03c3\u03c4\u03b7\u03bd \u03bf\u03c5\u03c1\u03ac \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2", + "Shuffle": "\u0391\u03bd\u03ac\u03bc\u03b9\u03be\u03b7", + "Identify": "\u0391\u03bd\u03b1\u03b3\u03bd\u03ce\u03c1\u03b9\u03c3\u03b7", + "EditImages": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03b5\u03b9\u03ba\u03cc\u03bd\u03c9\u03bd", + "EditMetadata": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03bc\u03b5\u03c4\u03b1\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd", + "Convert": "\u039c\u03b5\u03c4\u03b1\u03c4\u03c1\u03bf\u03c0\u03ae", + "Sync": "\u03a3\u03c5\u03b3\u03c7\u03c1\u03bf\u03bd\u03b9\u03c3\u03bc\u03cc\u03c2", + "InstantMix": "\u0386\u03bc\u03b5\u03c3\u03b7 Mix", + "ViewAlbum": "\u03a0\u03c1\u03bf\u03b2\u03bf\u03bb\u03ae \u03ac\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc", + "ViewArtist": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b7", + "QueueAllFromHere": "\u03a4\u03bf\u03c0\u03bf\u03b8\u03b5\u03c4\u03ae\u03c3\u03c4\u03b5 \u03c3\u03c4\u03b7\u03bd \u03bf\u03c5\u03c1\u03ac \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2 \u03cc\u03bb\u03b1 \u03b1\u03c0\u03cc \u03b5\u03b4\u03ce", + "PlayAllFromHere": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03b1\u03c0\u03cc \u03b5\u03b4\u03ce", + "PlayFromBeginning": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03b1\u03c0\u03cc \u03c4\u03b7\u03bd \u03b1\u03c1\u03c7\u03ae", + "ResumeAt": "\u03a3\u03c5\u03bd\u03ad\u03c7\u03b9\u03c3\u03b7 \u03b1\u03c0\u03cc {0}", + "RemoveFromPlaylist": "\u039a\u03b1\u03c4\u03ac\u03c1\u03b3\u03b7\u03c3\u03b7 \u03b1\u03c0\u03cc \u03c4\u03b7\u03bd \u03bf\u03c5\u03c1\u03ac", + "RemoveFromCollection": "\u039a\u03b1\u03c4\u03ac\u03c1\u03b3\u03b7\u03c3\u03b7 \u03b1\u03c0\u03cc \u03c4\u03b7\u03bd \u03c3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae", + "Sort": "\u03a4\u03b1\u03be\u03b9\u03bd\u03cc\u03bc\u03b7\u03c3\u03b7", + "Trailer": "\u03a4\u03c1\u03ad\u03ca\u03bb\u03b5\u03c1", + "MarkPlayed": "\u03ad\u03c7\u03b5\u03b9 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03c7\u03b8\u03b5\u03af", + "MarkUnplayed": "\u0394\u03b5\u03bd \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03ac\u03c7\u03b8\u03b7\u03ba\u03b5", + "GroupVersions": "\u039f\u03bc\u03b1\u03b4\u03b9\u03ba\u03ad\u03c2 \u03b5\u03ba\u03b4\u03cc\u03c3\u03b5\u03b9\u03c2", + "PleaseSelectTwoItems": "\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03c4\u03bf\u03c5\u03bb\u03ac\u03c7\u03b9\u03c3\u03c4\u03bf\u03bd \u03b4\u03cd\u03bf \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1.", + "TryMultiSelect": "\u0394\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03c0\u03bf\u03bb\u03bb\u03b1\u03c0\u03bb\u03ce\u03bd \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ce\u03bd", + "TryMultiSelectMessage": "\u0393\u03b9\u03b1 \u03bd\u03b1 \u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03c4\u03b5\u03af\u03c4\u03b5 \u03c0\u03bf\u03bb\u03bb\u03ac \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd, \u03b1\u03c0\u03bb\u03ac \u03ba\u03ac\u03bd\u03c4\u03b5 \u03ba\u03bb\u03b9\u03ba \u03ba\u03b1\u03b9 \u03ba\u03c1\u03b1\u03c4\u03ae\u03c3\u03c4\u03b5 \u03c0\u03b1\u03c4\u03b7\u03bc\u03ad\u03bd\u03bf \u03ba\u03ac\u03b8\u03b5 \u03b1\u03c6\u03af\u03c3\u03b1 \u03ba\u03b1\u03b9 \u03b5\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03c4\u03b1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03c0\u03bf\u03c5 \u03b8\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03c7\u03b5\u03b9\u03c1\u03b9\u03c3\u03c4\u03b5\u03af\u03c4\u03b5. \u0394\u03bf\u03ba\u03af\u03bc\u03b1\u03c3\u03ad \u03c4\u03bf!", + "HeaderConfirmRecordingCancellation": "\u0395\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03b9\u03ce\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b1\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2", + "MessageConfirmRecordingCancellation": "\u0395\u03af\u03c3\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03bf\u03b9 \u03cc\u03c4\u03b9 \u03b8\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03b1\u03ba\u03c5\u03c1\u03ce\u03c3\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03ae \u03c4\u03b7\u03bd \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae;", + "Error": "\u03a3\u03c6\u03ac\u03bb\u03bc\u03b1", + "VoiceInput": "\u0395\u03af\u03c3\u03bf\u03b4\u03bf\u03c2 \u0389\u03c7\u03bf\u03c5", + "LabelContentType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5:", + "LabelPath": "\u0394\u03b9\u03b1\u03b4\u03c1\u03bf\u03bc\u03ae:", + "Playlists": "\u039b\u03af\u03c3\u03c4\u03b5\u03c2 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2", + "LabelTitle": "\u03a4\u03af\u03c4\u03bb\u03bf\u03c2:", + "LabelOriginalTitle": "\u0391\u03c1\u03c7\u03b9\u03ba\u03cc\u03c2 \u03c4\u03af\u03c4\u03bb\u03bf\u03c2:", + "LabelSortTitle": "\u03a3\u03cd\u03bd\u03c4\u03bf\u03bc\u03bf\u03c2 \u03c4\u03af\u03c4\u03bb\u03bf\u03c2", + "LabelDateAdded": "\u0397\u03bc\u03b5\u03c1\u03bd\u03af\u03b1 \u03c0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7\u03c2:", + "DateAdded": "\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u03c0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7\u03c2", + "DatePlayed": "\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2", + "ConfigureDateAdded": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03c4\u03b5 \u03c4\u03b7 \u03c1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03c4\u03c1\u03cc\u03c0\u03bf\u03c5 \u03bc\u03b5 \u03c4\u03bf\u03bd \u03bf\u03c0\u03bf\u03af\u03bf \u03c0\u03c1\u03bf\u03c3\u03b4\u03b9\u03bf\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9 \u03b7 \u03b7\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u03c0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7\u03c2 \u03c3\u03c4\u03bf\u03bd \u03c0\u03af\u03bd\u03b1\u03ba\u03b1 \u03b5\u03bb\u03ad\u03b3\u03c7\u03bf\u03c5 \u03c4\u03bf\u03c5 Emby Server \u03c3\u03c4\u03b9\u03c2 \u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7\u03c2", + "LabelStatus": "\u039a\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7:", + "LabelArtists": "\u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2:", + "LabelArtistsHelp": "\u039e\u03b5\u03c7\u03c9\u03c1\u03af\u03c3\u03c4\u03b5 \u03c0\u03bf\u03bb\u03bb\u03b1\u03c0\u03bb\u03ac \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ce\u03bd\u03c4\u03b1\u03c2;", + "HeaderAlbumArtists": "\u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc \u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2", + "LabelAlbumArtists": "\u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc \u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2", + "LabelAlbum": "\u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc", + "Artists": "\u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2", + "ImdbRating": "\u0392\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1 IMDb", + "CommunityRating": "\u0392\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1 \u039a\u03bf\u03b9\u03bd\u03cc\u03c4\u03b7\u03c4\u03b1\u03c2", + "LabelCommunityRating": "\u0392\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1 \u039a\u03bf\u03b9\u03bd\u03cc\u03c4\u03b7\u03c4\u03b1\u03c2:", + "LabelCriticRating": "\u0392\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1 \u03ba\u03c1\u03b9\u03c4\u03b9\u03ba\u03ce\u03bd:", + "CriticRating": "\u0392\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1 \u03ba\u03c1\u03b9\u03c4\u03b9\u03ba\u03ce\u03bd", + "LabelWebsite": "\u0399\u03c3\u03c4\u03bf\u03c3\u03b5\u03bb\u03af\u03b4\u03b1:", + "LabelTagline": "\u0395\u03c4\u03b9\u03ba\u03ad\u03c4\u03b1:", + "LabelOverview": "\u0395\u03c0\u03b9\u03c3\u03ba\u03cc\u03c0\u03b7\u03c3\u03b7:", + "LabelShortOverview": "\u03a3\u03cd\u03bd\u03c4\u03bf\u03bc\u03b7 \u0395\u03c0\u03b9\u03c3\u03ba\u03cc\u03c0\u03b7\u03c3\u03b7", + "LabelReleaseDate": "\u0397\u03bc\u03ad\u03c1\u03b1 \u03ba\u03c5\u03ba\u03bb\u03bf\u03c6\u03bf\u03c1\u03af\u03b1\u03c2:", + "LabelYear": "\u0388\u03c4\u03bf\u03c2:", + "LabelPlaceOfBirth": "\u03a4\u03cc\u03c0\u03bf\u03c2 \u03b3\u03ad\u03bd\u03bd\u03b7\u03c3\u03b7\u03c2:", + "Aired": "\u03a0\u03c1\u03bf\u03b2\u03bb\u03ae\u03b8\u03b7\u03ba\u03b5", + "LabelAirDays": "\u0397\u03bc\u03ad\u03c1\u03b5\u03c2 \u03ba\u03c5\u03ba\u03bb\u03bf\u03c6\u03bf\u03c1\u03af\u03b1\u03c2:", + "LabelAirTime": "\u038f\u03c1\u03b1 \u03ba\u03c5\u03ba\u03bb\u03bf\u03c6\u03bf\u03c1\u03af\u03b1\u03c2", + "LabelRuntimeMinutes": "\u03a7\u03c1\u03cc\u03bd\u03bf\u03c2 \u03b5\u03ba\u03c4\u03ad\u03bb\u03b5\u03c3\u03b7\u03c2 (\u03bb\u03b5\u03c0\u03c4\u03ac):", + "LabelParentalRating": "\u0391\u03be\u03b9\u03bf\u03bb\u03cc\u03b3\u03b7\u03c3\u03b7 \u03b3\u03bf\u03bd\u03ad\u03c9\u03bd:", + "LabelCustomRating": "\u03a0\u03c1\u03bf\u03c3\u03b1\u03c1\u03bc\u03bf\u03c3\u03bc\u03ad\u03bd\u03b7 \u03b1\u03be\u03b9\u03bf\u03bb\u03cc\u03b3\u03b7\u03c3\u03b7:", + "LabelOriginalAspectRatio": "\u0391\u03c1\u03c7\u03b9\u03ba\u03cc\u03c2 \u03bb\u03cc\u03b3\u03bf\u03c2 \u03b4\u03b9\u03b1\u03c3\u03c4\u03ac\u03c3\u03b5\u03c9\u03bd:", + "Label3DFormat": "\u03a4\u03c1\u03b9\u03c3\u03b4\u03b9\u03ac\u03c3\u03c4\u03b1\u03c4\u03b7 \u03c6\u03cc\u03c1\u03bc\u03b1", + "FormatValue": "\u03a6\u03bf\u03c1\u03bc\u03ac\u03c4: {0}", + "DownloadsValue": "\u039b\u03ae\u03c8\u03b5\u03b9\u03c2: {0}", + "PerfectMatch": "\u03a4\u03ad\u03bb\u03b5\u03b9\u03b1 \u03b1\u03bd\u03c4\u03b9\u03c3\u03c4\u03bf\u03af\u03c7\u03b9\u03c3\u03b7", + "EnableExternalVideoPlayers": "\u0395\u03be\u03c9\u03c4\u03b5\u03c1\u03b9\u03ba\u03ac players \u03b3\u03b9\u03b1 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf", + "EnableExternalVideoPlayersHelp": "\u0388\u03bd\u03b1 \u03b5\u03be\u03c9\u03c4\u03b5\u03c1\u03b9\u03ba\u03cc \u03bc\u03b5\u03bd\u03bf\u03cd \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2 \u03b8\u03b1 \u03b5\u03bc\u03c6\u03b1\u03bd\u03b9\u03c3\u03c4\u03b5\u03af \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf.", + "HeaderSpecialEpisodeInfo": "\u0395\u03b9\u03b4\u03b9\u03ba\u03ad\u03c2 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03b5\u03c0\u03b5\u03b9\u03c3\u03bf\u03b4\u03af\u03bf\u03c5", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "\u0395\u03be\u03c9\u03c4\u03b5\u03c1\u03b9\u03ba\u03ac ids:", + "HeaderDisplaySettings": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7\u03c2", + "LabelDisplayOrder": "\u03a3\u03b5\u03b9\u03c1\u03ac \u03b5\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7\u03c2:", + "Display": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7", + "Countries": "\u03a7\u03ce\u03c1\u03b5\u03c2", + "Genres": "\u0395\u03af\u03b4\u03b7", + "Studios": "\u03a3\u03c4\u03bf\u03cd\u03bd\u03c4\u03b9\u03bf", + "Tags": "\u0395\u03c4\u03b9\u03ba\u03ad\u03c4\u03b5\u03c2", + "HeaderMetadataSettings": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03bc\u03b5\u03c4\u03b1\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd", + "People": "\u0386\u03bd\u03b8\u03c1\u03c9\u03c0\u03bf\u03b9 ", + "LabelMetadataDownloadLanguage": "\u03a0\u03c1\u03bf\u03c4\u03b9\u03bc\u03ce\u03bc\u03b5\u03bd\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1 \u03b5\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7\u03c2:", + "LabelLockItemToPreventChanges": "\u039a\u03bb\u03b5\u03af\u03b4\u03c9\u03bc\u03b1 \u03b1\u03c5\u03c4\u03bf\u03cd \u03c4\u03bf\u03c5 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf\u03c5 \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03b1\u03c0\u03bf\u03c4\u03c1\u03ad\u03c8\u03b5\u03c4\u03b5 \u03bc\u03b5\u03bb\u03bb\u03bf\u03bd\u03c4\u03b9\u03ba\u03ad\u03c2 \u03b1\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2", + "MessageLeaveEmptyToInherit": "\u0391\u03c6\u03ae\u03c3\u03c4\u03b5 \u03ba\u03b5\u03bd\u03cc \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03ba\u03bb\u03b7\u03c1\u03bf\u03bd\u03bf\u03bc\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b9\u03c2 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03b1\u03c0\u03cc \u03ad\u03bd\u03b1 \u03b3\u03bf\u03bd\u03b9\u03ba\u03cc \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03ae \u03c4\u03b7\u03bd \u03c0\u03b1\u03b3\u03ba\u03cc\u03c3\u03bc\u03b9\u03b1 \u03c0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03bc\u03ad\u03bd\u03b7 \u03c4\u03b9\u03bc\u03ae.", + "LabelCountry": "\u03a7\u03ce\u03c1\u03b1:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "\u0388\u03c4\u03bf\u03c2 \u0393\u03ad\u03bd\u03bd\u03b7\u03c3\u03b7\u03c2:", + "LabelBirthDate": "\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u0393\u03b5\u03bd\u03b5\u03b8\u03bb\u03af\u03c9\u03bd:", + "LabelDeathDate": "\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u0398\u03b1\u03bd\u03ac\u03c4\u03bf\u03c5:", + "LabelEndDate": "\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u039b\u03ae\u03be\u03b7\u03c2:", + "LabelSeasonNumber": "\u0391\u03c1\u03b9\u03b8\u03bc\u03cc\u03c2 \u03ba\u03cd\u03ba\u03bb\u03bf\u03c5:", + "LabelEpisodeNumber": "\u039d\u03bf\u03cd\u03bc\u03b5\u03c1\u03bf \u0395\u03c0\u03b5\u03b9\u03c3\u03bf\u03b4\u03af\u03bf\u03c5:", + "LabelTrackNumber": "\u0391\u03c1\u03b9\u03b8\u03bc\u03cc\u03c2 \u039a\u03bf\u03bc\u03bc\u03b1\u03c4\u03b9\u03bf\u03cd:", + "LabelNumber": "\u0391\u03c1\u03b9\u03b8\u03bc\u03cc\u03c2:", + "LabelDiscNumber": "\u0391\u03c1\u03b9\u03b8\u03bc\u03cc\u03c2 \u0394\u03af\u03c3\u03ba\u03bf\u03c5:", + "LabelParentNumber": "\u0391\u03c1\u03b9\u03b8\u03bc\u03cc\u03c2 \u03bc\u03b7\u03c4\u03c1\u03b9\u03ba\u03ae\u03c2:", + "SortName": "\u03a3\u03cd\u03bd\u03c4\u03bf\u03bc\u03bf\u03c2 \u03c4\u03af\u03c4\u03bb\u03bf\u03c2", + "ReleaseDate": "\u0397\u03bc\u03ad\u03c1\u03b1 \u03ba\u03c5\u03ba\u03bb\u03bf\u03c6\u03bf\u03c1\u03af\u03b1\u03c2", + "Continuing": "\u03a3\u03c5\u03bd\u03ad\u03c7\u03b9\u03c3\u03b7", + "Ended": "\u03a4\u03ad\u03bb\u03bf\u03c2", + "HeaderEnabledFields": "\u0395\u03bd\u03b5\u03c1\u03b3\u03ac \u03a0\u03b5\u03b4\u03af\u03b1", + "HeaderEnabledFieldsHelp": "\u039a\u03b1\u03c4\u03b1\u03c1\u03b3\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03b5\u03bd\u03cc\u03c2 \u03c0\u03b5\u03b4\u03af\u03bf\u03c5 \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03c4\u03bf \u03ba\u03bb\u03b5\u03b9\u03b4\u03ce\u03c3\u03b5\u03c4\u03b5 \u03ba\u03b1\u03b9 \u03bd\u03b1 \u03b1\u03c0\u03bf\u03c4\u03c1\u03ad\u03c8\u03b5\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b1\u03bb\u03bb\u03b1\u03b3\u03ae \u03c4\u03c9\u03bd \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd \u03c4\u03bf\u03c5.", + "Backdrops": "\u03a3\u03ba\u03b7\u03bd\u03b9\u03ba\u03ac", + "Images": "\u0395\u03b9\u03ba\u03cc\u03bd\u03b5\u03c2", + "Runtime": "\u03a7\u03c1\u03cc\u03bd\u03bf\u03c2 \u03b5\u03ba\u03c4\u03ad\u03bb\u03b5\u03c3\u03b7\u03c2", + "ProductionLocations": "\u03a4\u03bf\u03c0\u03bf\u03b8\u03b5\u03c3\u03af\u03b5\u03c2 \u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2", + "BirthLocation": "\u03a4\u03cc\u03c0\u03bf\u03c2 \u03b3\u03ad\u03bd\u03bd\u03b7\u03c3\u03b7\u03c2:", + "ParentalRating": "\u039a\u03b1\u03c4\u03b1\u03bb\u03bb\u03b7\u03bb\u03cc\u03c4\u03b7\u03c4\u03b1", + "PlayCount": "\u039a\u03b1\u03c4\u03b1\u03bc\u03ad\u03c4\u03c1\u03b7\u03c3\u03b7 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2", + "Name": "\u038c\u03bd\u03bf\u03bc\u03b1", + "Overview": "\u0395\u03c0\u03b9\u03c3\u03ba\u03cc\u03c0\u03b7\u03c3\u03b7", + "LabelType": "\u03a4\u03cd\u03c0\u03bf\u03c2:", + "LabelPersonRole": "\u03a1\u03cc\u03bb\u03bf\u03c2:", + "LabelPersonRoleHelp": "\u03a0\u03b1\u03c1\u03ac\u03b4\u03b5\u03b9\u03b3\u03bc\u03b1: \u03bf\u03b4\u03b7\u03b3\u03cc\u03c2 \u03c6\u03bf\u03c1\u03c4\u03b7\u03b3\u03bf\u03cd \u03c0\u03b1\u03b3\u03c9\u03c4\u03bf\u03cd", + "Actor": "\u0397\u03b8\u03bf\u03c0\u03bf\u03b9\u03cc\u03c2", + "Composer": "\u03a3\u03c5\u03bd\u03b8\u03ad\u03c4\u03b7\u03c2", + "Director": "\u03a3\u03ba\u03b7\u03bd\u03bf\u03b8\u03ad\u03c4\u03b7\u03c2", + "GuestStar": "\u03a6\u03b9\u03bb\u03b9\u03ba\u03ae \u03a3\u03c5\u03bc\u03bc\u03b5\u03c4\u03bf\u03c7\u03ae", + "Producer": "\u03a0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03cc\u03c2", + "Writer": "\u03a3\u03c5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ad\u03b1\u03c2", + "MessageNoSyncJobsFound": "\u0394\u03b5\u03bd \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b1\u03bd \u03bb\u03ae\u03c8\u03b5\u03b9\u03c2. \u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03c3\u03c4\u03b5 \u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b5\u03c2 \u03bb\u03ae\u03c8\u03b7\u03c2 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ce\u03bd\u03c4\u03b1\u03c2 \u03c4\u03b1 \u03ba\u03bf\u03c5\u03bc\u03c0\u03b9\u03ac \u03bb\u03ae\u03c8\u03b7\u03c2 \u03c0\u03bf\u03c5 \u03b2\u03c1\u03af\u03c3\u03ba\u03bf\u03bd\u03c4\u03b1\u03b9 \u03c3\u03b5 \u03bf\u03bb\u03cc\u03ba\u03bb\u03b7\u03c1\u03b7 \u03c4\u03b7\u03bd \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae.", + "MessageNoDownloadsFound": "\u0394\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03bd \u03bb\u03ae\u03c8\u03b5\u03b9\u03c2 \u03b5\u03ba\u03c4\u03cc\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2. \u039a\u03ac\u03bd\u03c4\u03b5 \u03bb\u03ae\u03c8\u03b7 \u03c4\u03bf\u03c5 \u03bc\u03ad\u03c3\u03bf\u03c5 \u03b5\u03ba\u03c4\u03cd\u03c0\u03c9\u03c3\u03b7\u03c2 \u03b3\u03b9\u03b1 \u03c7\u03c1\u03ae\u03c3\u03b7 \u03b5\u03ba\u03c4\u03cc\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2 \u03ba\u03ac\u03bd\u03bf\u03bd\u03c4\u03b1\u03c2 \u03ba\u03bb\u03b9\u03ba \u03c3\u03c4\u03b7\u03bd \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u039b\u03ae\u03c8\u03b7 \u03c3\u03b5 \u03bf\u03bb\u03cc\u03ba\u03bb\u03b7\u03c1\u03b7 \u03c4\u03b7\u03bd \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae.", + "InstallingPackage": "\u0395\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 {0}", + "PackageInstallCompleted": "\u0397 \u03b5\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 {0} \u03bf\u03bb\u03bf\u03ba\u03bb\u03b7\u03c1\u03ce\u03b8\u03b7\u03ba\u03b5.", + "PackageInstallFailed": "{0} \u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1", + "PackageInstallCancelled": "\u0397 \u03b5\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 {0} \u03b1\u03ba\u03c5\u03c1\u03ce\u03b8\u03b7\u03ba\u03b5.", + "SeriesYearToPresent": "{0} - \u03b5\u03bc\u03c6\u03b1\u03bd\u03af\u03c3\u03c4\u03b7\u03ba\u03b5", + "ValueOneItem": "1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf", + "ValueOneSong": "1 \u03c4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9", + "ValueSongCount": "{0} \u03c4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1", + "ValueOneMovie": "1 \u03c4\u03b1\u03b9\u03bd\u03af\u03b1", + "ValueMovieCount": "{0} \u03c4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2", + "ValueOneSeries": "1 \u03a3\u03b5\u03b9\u03c1\u03ac", + "ValueSeriesCount": "{0} \u03a3\u03b5\u03b9\u03c1\u03ad\u03c2", + "ValueOneEpisode": "1 \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03bf", + "ValueEpisodeCount": "{0} \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1", + "ValueOneGame": "1 \u03c0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9", + "ValueGameCount": "{0} \u03c0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9\u03b1", + "ValueOneAlbum": "1 \u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc", + "ValueAlbumCount": "{0} \u03ac\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc", + "ValueOneMusicVideo": "1 \u03bc\u03bf\u03c5\u03c3\u03b9\u03ba\u03cc \u03b2\u03af\u03bd\u03c4\u03b5\u03bf", + "ValueMusicVideoCount": "{0} \u03bc\u03bf\u03c5\u03c3\u03b9\u03ba\u03ac \u03b2\u03af\u03bd\u03c4\u03b5\u03bf", + "ValueMinutes": "{0} \u03bb\u03b5\u03c0\u03c4\u03ac", + "Albums": "\u0391\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc\u03c2", + "Songs": "\u03a4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1", + "Books": "\u0392\u03b9\u03b2\u03bb\u03af\u03b1", + "HeaderAudioBooks": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ac \u0392\u03b9\u03b2\u03bb\u03af\u03b1", + "HeaderIdentifyItemHelp": "\u03a0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03ae\u03c3\u03c4\u03b5 \u03ad\u03bd\u03b1 \u03ae \u03c0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b1 \u03ba\u03c1\u03b9\u03c4\u03ae\u03c1\u03b9\u03b1 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2. \u039a\u03b1\u03c4\u03ac\u03c1\u03b3\u03b7\u03c3\u03b7 \u03ba\u03c1\u03b9\u03c4\u03b7\u03c1\u03af\u03c9\u03bd \u03b3\u03b9\u03b1 \u03c4\u03b7\u03bd \u03b1\u03cd\u03be\u03b7\u03c3\u03b7 \u03c4\u03c9\u03bd \u03b1\u03c0\u03bf\u03c4\u03b5\u03bb\u03b5\u03c3\u03bc\u03ac\u03c4\u03c9\u03bd \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2.", + "PleaseEnterNameOrId": "\u0395\u03b9\u03c3\u03b1\u03b3\u03ac\u03b3\u03b5\u03c4\u03b5 \u03ad\u03bd\u03b1 \u03cc\u03bd\u03bf\u03bc\u03b1 \u03ae \u03ad\u03bd\u03b1 \u03b5\u03be\u03c9\u03c4\u03b5\u03c1\u03b9\u03ba\u03cc \u03b1\u03bd\u03b1\u03b3\u03bd\u03c9\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc.", + "MessageItemSaved": "\u03a4\u03bf \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03cd\u03c4\u03b7\u03ba\u03b5", + "SearchResults": "\u0391\u03c0\u03bf\u03c4\u03b5\u03bb\u03ad\u03c3\u03bc\u03b1\u03c4\u03b1 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2", + "ServerNameIsRestarting": "\u039f \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae\u03c2 Emby - {0} \u03b5\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03b9\u03bd\u03b5\u03af\u03c4\u03b1\u03b9.", + "ServerNameIsShuttingDown": "\u039f \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae\u03c2 Emby - {0} \u03c4\u03b5\u03c1\u03bc\u03b1\u03c4\u03af\u03b6\u03b5\u03c4\u03b1\u03b9.", + "HeaderDeleteItems": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03c9\u03bd", + "ConfirmDeleteItems": "\u0397 \u03b4\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03b1\u03c5\u03c4\u03ce\u03bd \u03c4\u03c9\u03bd \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03c9\u03bd \u03b8\u03b1 \u03c4\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03b9 \u03c4\u03cc\u03c3\u03bf \u03b1\u03c0\u03cc \u03c4\u03bf \u03c3\u03cd\u03c3\u03c4\u03b7\u03bc\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd \u03cc\u03c3\u03bf \u03ba\u03b1\u03b9 \u03b1\u03c0\u03cc \u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd \u03c3\u03b1\u03c2. \u0395\u03af\u03c3\u03c4\u03b5 \u03b2\u03ad\u03b2\u03b1\u03b9\u03bf\u03b9 \u03cc\u03c4\u03b9 \u03b8\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03c3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03b5\u03c4\u03b5;", + "PleaseRestartServerName": "\u039a\u03ac\u03bd\u03c4\u03b5 \u03b5\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03c4\u03bf\u03c5 Emby Server - {0}.", + "LabelSyncJobName": "\u038c\u03bd\u03bf\u03bc\u03b1 \u0395\u03c1\u03b3\u03b1\u03c3\u03af\u03b1\u03c2 \u03a3\u03c5\u03b3\u03c7\u03c1\u03bf\u03bd\u03b9\u03c3\u03bc\u03bf\u03cd:", + "SyncingDots": "\u03a3\u03c5\u03b3\u03c7\u03c1\u03bf\u03bd\u03b9\u03c3\u03bc\u03cc\u03c2...", + "ConvertingDots": "\u039c\u03b5\u03c4\u03b1\u03c4\u03c1\u03bf\u03c0\u03ae...", + "LabelQuality": "\u03a0\u03bf\u03b9\u03cc\u03c4\u03b7\u03c4\u03b1:", + "LabelSyncNoTargetsHelp": "\u03a6\u03b1\u03af\u03bd\u03b5\u03c4\u03b1\u03b9 \u03cc\u03c4\u03b9 \u03b4\u03b5\u03bd \u03b4\u03b9\u03b1\u03b8\u03ad\u03c4\u03b5\u03c4\u03b5 \u03b5\u03c0\u03af \u03c4\u03bf\u03c5 \u03c0\u03b1\u03c1\u03cc\u03bd\u03c4\u03bf\u03c2 \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ad\u03c2 \u03c0\u03bf\u03c5 \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03bf\u03c5\u03bd \u03bb\u03ae\u03c8\u03b7 \u03c7\u03c9\u03c1\u03af\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7.", + "DownloadingDots": "\u039b\u03ae\u03c8\u03b7...", + "HeaderSyncRequiresSub": "\u0397 \u03bb\u03ae\u03c8\u03b7 \u03b1\u03c0\u03b1\u03b9\u03c4\u03b5\u03af \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae Emby Premiere.", + "LearnMore": "\u03a0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b1 ", + "LabelProfile": "\u03a0\u03c1\u03bf\u03c6\u03b9\u03bb:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "\u039c\u03b5\u03c4\u03b1\u03c4\u03c1\u03bf\u03c0\u03ae \u03bc\u03cc\u03bd\u03bf \u03c4\u03c9\u03bd \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03c0\u03bf\u03c5 \u03b4\u03b5\u03bd \u03ad\u03c7\u03c9 \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03ae\u03c3\u03b5\u03b9", + "SyncUnwatchedVideosOnly": "\u039a\u03ac\u03bd\u03c4\u03b5 \u03bb\u03ae\u03c8\u03b7 \u03bc\u03cc\u03bd\u03bf \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03c0\u03bf\u03c5 \u03b4\u03b5\u03bd \u03ad\u03c7\u03bf\u03c5\u03bd \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03c7\u03b8\u03b5\u03af", + "ConvertUnwatchedVideosOnlyHelp": "\u039c\u03cc\u03bd\u03bf \u03c4\u03b1 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03c0\u03bf\u03c5 \u03b4\u03b5\u03bd \u03ad\u03c7\u03c9 \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03ae\u03c3\u03b5\u03b9 \u03b8\u03b1 \u03bc\u03b5\u03c4\u03b1\u03c4\u03c1\u03b1\u03c0\u03bf\u03cd\u03bd.", + "SyncUnwatchedVideosOnlyHelp": "\u0398\u03b1 \u03c0\u03c1\u03b1\u03b3\u03bc\u03b1\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03b8\u03bf\u03cd\u03bd \u03bb\u03ae\u03c8\u03b7 \u03bc\u03cc\u03bd\u03bf \u03bc\u03b7 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03c7\u03b8\u03ad\u03bd\u03c4\u03c9\u03bd \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03ba\u03b1\u03b9 \u03c4\u03b1 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b8\u03b1 \u03ba\u03b1\u03c4\u03b1\u03c1\u03b3\u03b7\u03b8\u03bf\u03cd\u03bd \u03b1\u03c0\u03cc \u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03ba\u03b1\u03b8\u03ce\u03c2 \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03bf\u03cd\u03bd\u03c4\u03b1\u03b9.", + "AutomaticallySyncNewContent": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b7 \u03bb\u03ae\u03c8\u03b7 \u03bd\u03ad\u03bf\u03c5 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5", + "AutomaticallySyncNewContentHelp": "\u03a4\u03bf \u03bd\u03ad\u03bf \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf \u03c0\u03bf\u03c5 \u03c0\u03c1\u03bf\u03c3\u03c4\u03af\u03b8\u03b5\u03c4\u03b1\u03b9 \u03c3\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf \u03c6\u03ac\u03ba\u03b5\u03bb\u03bf \u03b8\u03b1 \u03bc\u03b5\u03c4\u03b1\u03c6\u03bf\u03c1\u03c4\u03c9\u03b8\u03b5\u03af \u03b1\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b1 \u03c3\u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae.", + "AutomaticallyConvertNewContent": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b7 \u03bc\u03b5\u03c4\u03b1\u03c4\u03c1\u03bf\u03c0\u03ae \u03bd\u03ad\u03bf\u03c5 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5", + "AutomaticallyConvertNewContentHelp": "\u03a4\u03bf \u03bd\u03ad\u03bf \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf \u03c0\u03bf\u03c5 \u03c0\u03c1\u03bf\u03c3\u03c4\u03af\u03b8\u03b5\u03c4\u03b1\u03b9 \u03c3\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf \u03c6\u03ac\u03ba\u03b5\u03bb\u03bf \u03b8\u03b1 \u03bc\u03b5\u03c4\u03b1\u03c4\u03ad\u03c0\u03b5\u03c4\u03b1\u03b9 \u03b1\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b1.", + "LabelItemLimit": "\u038c\u03c1\u03b9\u03bf \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf\u03c5:", + "ConvertItemLimitHelp": "\u03a0\u03c1\u03bf\u03b1\u03b9\u03c1\u03b5\u03c4\u03b9\u03ba\u03cc. \u039f\u03c1\u03af\u03c3\u03c4\u03b5 \u03ad\u03bd\u03b1 \u03cc\u03c1\u03b9\u03bf \u03c3\u03c4\u03bf\u03bd \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc \u03c4\u03c9\u03bd \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03c9\u03bd \u03c0\u03bf\u03c5 \u03b8\u03b1 \u03bc\u03b5\u03c4\u03b1\u03c4\u03c1\u03b1\u03c0\u03bf\u03cd\u03bd.", + "DownloadItemLimitHelp": "\u03a0\u03c1\u03bf\u03b1\u03b9\u03c1\u03b5\u03c4\u03b9\u03ba\u03cc. \u039f\u03c1\u03af\u03c3\u03c4\u03b5 \u03ad\u03bd\u03b1 \u03cc\u03c1\u03b9\u03bf \u03c3\u03c4\u03bf\u03bd \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc \u03c4\u03c9\u03bd \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03c9\u03bd \u03c0\u03bf\u03c5 \u03b8\u03b1 \u03bb\u03b7\u03c6\u03b8\u03bf\u03cd\u03bd.", + "PleaseSelectDeviceToSyncTo": "\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03bc\u03b9\u03b1 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03b3\u03b9\u03b1 \u03c4\u03b7\u03bd \u03bf\u03c0\u03bf\u03af\u03b1 \u03b8\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03ba\u03ac\u03bd\u03b5\u03c4\u03b5 \u03bb\u03ae\u03c8\u03b7.", + "Screenshots": "\u03a3\u03c4\u03b9\u03b3\u03bc\u03b9\u03cc\u03c4\u03c5\u03c0\u03b1 \u03bf\u03b8\u03cc\u03bd\u03b7\u03c2", + "MoveRight": "\u039c\u03b5\u03c4\u03b1\u03ba\u03b9\u03bd\u03ae\u03c3\u03c4\u03b5 \u03b4\u03b5\u03be\u03b9\u03ac", + "MoveLeft": "\u039a\u03b9\u03bd\u03ae\u03c3\u03bf\u03c5 \u03b1\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03ac", + "ConfirmDeleteImage": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2;", + "HeaderEditImages": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03b5\u03b9\u03ba\u03cc\u03bd\u03c9\u03bd", + "Settings": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2", + "ShowIndicatorsFor": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03b4\u03b5\u03b9\u03ba\u03c4\u03ce\u03bd \u03b3\u03b9\u03b1:", + "NewEpisodes": "\u039d\u03ad\u03b1 \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1", + "Episodes": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1", + "HDPrograms": "\u03a0\u03c1\u03bf\u03b3\u03c1\u03ac\u03bc\u03bc\u03b1\u03c4\u03b1 \u03a5\u03c8\u03b7\u03bb\u03ae\u03c2 \u0391\u03bd\u03ac\u03bb\u03c5\u03c3\u03b7\u03c2", + "Programs": "\u03a0\u03c1\u03bf\u03b3\u03c1\u03ac\u03bc\u03bc\u03b1\u03c4\u03b1", + "LiveBroadcasts": "\u0396\u03c9\u03bd\u03c4\u03b1\u03bd\u03ad\u03c2 \u03b5\u03ba\u03c0\u03bf\u03bc\u03c0\u03ad\u03c2", + "Premieres": "\u03a0\u03c1\u03b5\u03bc\u03b9\u03ad\u03c1\u03b5\u03c2", + "RepeatEpisodes": "\u0395\u03c0\u03b1\u03bd\u03ac\u03bb\u03b7\u03c8\u03b7 \u03b5\u03c0\u03b5\u03b9\u03c3\u03bf\u03b4\u03af\u03c9\u03bd", + "DvrSubscriptionRequired": "\u03a4\u03bf Emby DVR \u03b1\u03c0\u03b1\u03b9\u03c4\u03b5\u03af \u03bc\u03b9\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae Emby Premiere.", + "HeaderCancelRecording": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2", + "CancelRecording": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2", + "HeaderKeepRecording": "\u03a3\u03c5\u03bd\u03ad\u03c7\u03b9\u03c3\u03b5 \u03c4\u03b7\u03bd \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae", + "HeaderCancelSeries": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 \u03a3\u03b5\u03b9\u03c1\u03ac\u03c2", + "HeaderKeepSeries": "\u03a3\u03c5\u03bd\u03ad\u03c7\u03b9\u03c3\u03b5 \u03c4\u03b7\u03bd \u03a3\u03b5\u03b9\u03c1\u03ac", + "HeaderLearnMore": "\u03a0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b1 ", + "DeleteMedia": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd", + "SeriesSettings": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03a3\u03b5\u03b9\u03c1\u03ce\u03bd", + "HeaderRecordingOptions": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ad\u03c2 \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2", + "CancelSeries": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 \u03a3\u03b5\u03b9\u03c1\u03ac\u03c2", + "DoNotRecord": "\u039c\u03b7\u03bd \u03b5\u03b3\u03b3\u03c1\u03ac\u03c8\u03b5\u03b9\u03c2", + "HeaderSeriesOptions": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ad\u03c2 \u03a3\u03b5\u03b9\u03c1\u03ce\u03bd", + "LabelChannels": "\u039a\u03b1\u03bd\u03ac\u03bb\u03b9\u03b1:", + "ChannelNameOnly": "\u039c\u03cc\u03bd\u03bf \u03c4\u03bf {0} \u03ba\u03b1\u03bd\u03ac\u03bb\u03b9", + "Anytime": "\u039f\u03c0\u03bf\u03c4\u03b5\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5", + "AnyLanguage": "\u039f\u03c0\u03bf\u03b9\u03b1\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1", + "AroundTime": "\u03a0\u03b5\u03c1\u03af\u03c0\u03bf\u03c5 {0}", + "All": "\u038c\u03bb\u03b1", + "AllChannels": "\u038c\u03bb\u03b1 \u03c4\u03b1 \u03ba\u03b1\u03bd\u03ac\u03bb\u03b9\u03b1", + "LabelRecord": "\u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae:", + "NewEpisodesOnly": "\u039d\u03ad\u03b1 \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1 \u03bc\u03cc\u03bd\u03bf", + "AllEpisodes": "\u039f\u03bb\u03b1 \u03c4\u03b1 \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1", + "LabelStartWhenPossible": "\u0388\u03bd\u03b1\u03c1\u03be\u03b7 \u03cc\u03c4\u03b1\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03cc:", + "LabelStopWhenPossible": "\u0394\u03b9\u03b1\u03ba\u03bf\u03c0\u03ae \u03cc\u03c4\u03b1\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03cc\u03bd:", + "MinutesBefore": "\u03bb\u03b5\u03c0\u03c4\u03ac \u03c0\u03c1\u03b9\u03bd", + "MinutesAfter": "\u03bb\u03b5\u03c0\u03c4\u03ac \u03bc\u03b5\u03c4\u03ac", + "SkipEpisodesAlreadyInMyLibrary": "\u039c\u03b7\u03bd \u03ba\u03b1\u03c4\u03b1\u03b3\u03c1\u03ac\u03c6\u03b5\u03c4\u03b5 \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1 \u03c0\u03bf\u03c5 \u03b2\u03c1\u03af\u03c3\u03ba\u03bf\u03bd\u03c4\u03b1\u03b9 \u03ae\u03b4\u03b7 \u03c3\u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7 \u03bc\u03bf\u03c5", + "SkipEpisodesAlreadyInMyLibraryHelp": "\u03a4\u03b1 \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1 \u03b8\u03b1 \u03c3\u03c5\u03b3\u03ba\u03c1\u03b9\u03b8\u03bf\u03cd\u03bd \u03bc\u03b5 \u03c4\u03bf\u03c5\u03c2 \u03b1\u03c1\u03b9\u03b8\u03bc\u03bf\u03cd\u03c2 \u03ba\u03cd\u03ba\u03bb\u03bf\u03c5 \u03ba\u03b1\u03b9 \u03b5\u03c0\u03b5\u03b9\u03c3\u03bf\u03b4\u03af\u03c9\u03bd, \u03cc\u03c4\u03b1\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03b9\u03b1\u03b8\u03ad\u03c3\u03b9\u03bc\u03bf\u03b9.", + "LabelKeepUpTo": "\u03a3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03c4\u03b5:", + "AsManyAsPossible": "\u039f\u03c3\u03bf \u03c4\u03bf \u03b4\u03c5\u03bd\u03b1\u03c4\u03bf\u03bd \u03c0\u03b5\u03c1\u03b9\u03c3\u03c3\u03bf\u03c4\u03b5\u03c1\u03b1", + "DefaultErrorMessage": "\u03a0\u03b1\u03c1\u03bf\u03c5\u03c3\u03b9\u03ac\u03c3\u03c4\u03b7\u03ba\u03b5 \u03c3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03c4\u03bf\u03c5 \u03b1\u03b9\u03c4\u03ae\u03bc\u03b1\u03c4\u03cc\u03c2 \u03c3\u03b1\u03c2. \u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03b4\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03c4\u03b5 \u03be\u03b1\u03bd\u03ac \u03b1\u03c1\u03b3\u03cc\u03c4\u03b5\u03c1\u03b1.", + "LabelKeep:": "\u03a3\u03c5\u03bd\u03ad\u03c7\u03b9\u03c3\u03b5:", + "UntilIDelete": "\u039c\u03ad\u03c7\u03c1\u03b9 \u03bd\u03b1 \u03c4\u03bf \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03c9", + "UntilSpaceNeeded": "\u039c\u03ad\u03c7\u03c1\u03b9 \u03bd\u03b1 \u03c7\u03c1\u03b5\u03b9\u03b1\u03c3\u03c4\u03b5\u03af \u03ba\u03b1\u03b9 \u03ac\u03bb\u03bb\u03bf\u03c2 \u03c7\u03ce\u03c1\u03bf\u03c2", + "Categories": "\u039a\u03b1\u03c4\u03b7\u03b3\u03bf\u03c1\u03af\u03b5\u03c2", + "Sports": "\u03a3\u03c0\u03cc\u03c1", + "News": "\u039d\u03ad\u03b1", + "Movies": "\u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2", + "Kids": "\u03a0\u03b1\u03b9\u03b4\u03b9\u03ba\u03ac", + "EnableColorCodedBackgrounds": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b1 \u03ad\u03b3\u03c7\u03c1\u03c9\u03bc\u03b1 \u03ba\u03c9\u03b4\u03b9\u03ba\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b1 \u03c6\u03cc\u03bd\u03c4\u03b1", + "SortChannelsBy": "\u03a3\u03c4\u03bf\u03af\u03c7\u03b9\u03c3\u03b7 \u03ba\u03b1\u03bd\u03b1\u03bb\u03b9\u03ce\u03bd \u03bc\u03b5:", + "RecentlyWatched": "\u03a0\u03c1\u03cc\u03c3\u03c6\u03b1\u03c4\u03b1 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03c7\u03b8\u03ad\u03bd\u03c4\u03b1", + "ChannelNumber": "\u0391\u03c1\u03b9\u03b8\u03bc\u03cc\u03c2 \u03ba\u03b1\u03bd\u03b1\u03bb\u03b9\u03bf\u03cd", + "HeaderBenefitsEmbyPremiere": "\u039f\u03c6\u03ad\u03bb\u03b7 \u03b1\u03c0\u03cc \u03c4\u03b7\u03bd \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "\u0391\u03c0\u03bf\u03bb\u03b1\u03cd\u03c3\u03c4\u03b5 \u03ad\u03bd\u03b1 \u03bb\u03b5\u03c0\u03c4\u03cc \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2. \u03a3\u03b1\u03c2 \u03b5\u03c5\u03c7\u03b1\u03c1\u03b9\u03c3\u03c4\u03ce \u03c0\u03bf\u03c5 \u03b4\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03b1\u03c4\u03b5 \u03c4\u03bf\u03bd Emby.", + "HeaderTryPlayback": "\u0394\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae", + "HowDidYouPay": "\u03a0\u03ce\u03c2 \u03c0\u03bb\u03b7\u03c1\u03ce\u03c3\u03b1\u03c4\u03b5;", + "IHaveEmbyPremiere": "\u0388\u03c7\u03c9 Emby Premiere", + "IPurchasedThisApp": "\u0391\u03b3\u03cc\u03c1\u03b1\u03c3\u03b1 \u03b1\u03c5\u03c4\u03ae\u03bd \u03c4\u03b7\u03bd \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae", + "ButtonRestorePreviousPurchase": "\u0395\u03c0\u03b1\u03bd\u03b1\u03c6\u03bf\u03c1\u03ac \u03b1\u03b3\u03bf\u03c1\u03ac\u03c2", + "ButtonUnlockWithPurchase": "\u039e\u03b5\u03ba\u03bb\u03b5\u03b9\u03b4\u03ce\u03c3\u03c4\u03b5 \u03bc\u03b5 \u03c4\u03b7\u03bd \u03b1\u03b3\u03bf\u03c1\u03ac", + "ButtonUnlockPrice": "\u039e\u03b5\u03ba\u03bb\u03b5\u03af\u03b4\u03c9\u03bc\u03b1 {0}", + "EmbyPremiereMonthlyWithPrice": "Emmy Premiere \u039c\u03b7\u03bd\u03b9\u03b1\u03af\u03b1 {0}", + "HeaderAlreadyPaid": "\u0389\u03b4\u03b7 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03c0\u03bb\u03b7\u03c1\u03ce\u03c3\u03b5\u03b9;", + "ButtonPlayOneMinute": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03b3\u03b9\u03b1 \u03ad\u03bd\u03b1 \u03bb\u03b5\u03c0\u03c4\u03cc", + "PlaceFavoriteChannelsAtBeginning": "\u03a4\u03bf\u03c0\u03bf\u03b8\u03b5\u03c4\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b1 \u03b1\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1 \u03ba\u03b1\u03bd\u03ac\u03bb\u03b9\u03b1 \u03c3\u03c4\u03b7\u03bd \u03b1\u03c1\u03c7\u03ae", + "HeaderUnlockFeature": "\u039e\u03b5\u03ba\u03bb\u03b5\u03af\u03b4\u03c9\u03bc\u03b1 \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03b7\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03ce\u03bd", + "MessageDidYouKnowCinemaMode": "\u0393\u03bd\u03c9\u03c1\u03af\u03b6\u03b1\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03bc\u03b5 \u03c4\u03bf Emby Premiere, \u03bc\u03c0\u03bf\u03c1\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03b2\u03b5\u03bb\u03c4\u03b9\u03ce\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b5\u03bc\u03c0\u03b5\u03b9\u03c1\u03af\u03b1 \u03c3\u03b1\u03c2 \u03bc\u03b5 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b5\u03c2 \u03cc\u03c0\u03c9\u03c2 \u03c4\u03bf Cinema Mode;", + "MessageDidYouKnowCinemaMode2": "\u0397 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u039a\u03b9\u03bd\u03b7\u03bc\u03b1\u03c4\u03bf\u03b3\u03c1\u03ac\u03c6\u03bf\u03c5 \u03c3\u03ac\u03c2 \u03c0\u03c1\u03bf\u03c3\u03c6\u03ad\u03c1\u03b5\u03b9 \u03c4\u03b7\u03bd \u03c0\u03c1\u03b1\u03b3\u03bc\u03b1\u03c4\u03b9\u03ba\u03ae \u03ba\u03b9\u03bd\u03b7\u03bc\u03b1\u03c4\u03bf\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03ae \u03b5\u03bc\u03c0\u03b5\u03b9\u03c1\u03af\u03b1 \u03bc\u03b5 \u03c4\u03c1\u03ad\u03b9\u03bb\u03b5\u03c1 \u03ba\u03b1\u03b9 \u03c0\u03c1\u03bf\u03c3\u03b1\u03c1\u03bc\u03bf\u03c3\u03bc\u03ad\u03bd\u03b1 intros \u03c0\u03c1\u03b9\u03bd \u03b1\u03c0\u03cc \u03c4\u03b7 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1.", + "HeaderPlayMyMedia": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03c4\u03c9\u03bd \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd \u03bc\u03bf\u03c5", + "HeaderDiscoverEmbyPremiere": "\u03b1\u03bd\u03b1\u03ba\u03b1\u03bb\u03cd\u03c8\u03c4\u03b5 \u03c4\u03bf Emby Premiere", + "Items": "\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1", + "OneChannel": "\u0388\u03bd\u03b1 \u03ba\u03b1\u03bd\u03ac\u03bb\u03b9", + "ConfirmRemoveDownload": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03bb\u03ae\u03c8\u03b7\u03c2;", + "RemoveDownload": "\u0394\u03b9\u03ad\u03b3\u03c1\u03b1\u03c8\u03b5 \u03c4\u03b7 \u03bb\u03ae\u03c8\u03b7", + "KeepDownload": "\u03a3\u03c5\u03bd\u03ad\u03c7\u03b5\u03b9\u03b1 \u03bb\u03ae\u03c8\u03b7\u03c2", + "AddedOnValue": "\u03a0\u03c1\u03bf\u03c3\u03c4\u03ad\u03b8\u03b7\u03ba\u03b5 {0}", + "RemovingFromDevice": "\u0391\u03c6\u03b1\u03af\u03c1\u03b5\u03c3\u03b7 \u03b1\u03c0\u03cc \u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae", + "KeepOnDevice": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03c3\u03b5 \u03b1\u03c5\u03c4\u03ae \u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae", + "CancelDownload": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 \u03bb\u03ae\u03c8\u03b7\u03c2", + "SyncJobItemStatusReadyToTransfer": "\u0388\u03c4\u03bf\u03b9\u03bc\u03bf \u03b3\u03b9\u03b1 \u03bc\u03b5\u03c4\u03b1\u03c6\u03bf\u03c1\u03ac", + "SyncJobItemStatusSyncedMarkForRemoval": "\u0391\u03c6\u03b1\u03af\u03c1\u03b5\u03c3\u03b7 \u03b1\u03c0\u03cc \u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae", + "SyncJobItemStatusQueued": "\u03a3\u03c4\u03b7\u03bd \u03bf\u03c5\u03c1\u03ac", + "SyncJobItemStatusConverting": "\u039c\u03b5\u03c4\u03b1\u03c4\u03c1\u03bf\u03c0\u03ae", + "SyncJobItemStatusTransferring": "\u039c\u03b5\u03c4\u03b1\u03c6\u03bf\u03c1\u03ac", + "SyncJobItemStatusSynced": "\u039b\u03ae\u03c6\u03b8\u03b7\u03ba\u03b1\u03bd", + "SyncJobItemStatusFailed": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1", + "SyncJobItemStatusRemovedFromDevice": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03b1\u03c0\u03bf \u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae", + "SyncJobItemStatusCancelled": "\u0391\u03ba\u03c5\u03c1\u03ce\u03b8\u03b7\u03ba\u03b1\u03bd", + "Retry": "\u039e\u03b1\u03bd\u03b1\u03b4\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03b5\u03c4\u03b5", + "HeaderMyDevice": "\u0397 \u03a3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03bc\u03bf\u03c5", + "Continue": "\u03a3\u03c5\u03bd\u03ad\u03c7\u03b5\u03b9\u03b1", + "ContinueInSecondsValue": "\u03a3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03c4\u03b5 \u03c3\u03b5 {0} \u03b4\u03b5\u03c5\u03c4\u03b5\u03c1\u03cc\u03bb\u03b5\u03c0\u03c4\u03b1.", + "HeaderRemoteControl": "\u03a4\u03b7\u03bb\u03b5\u03c7\u03b5\u03b9\u03c1\u03b9\u03c3\u03c4\u03ae\u03c1\u03b9\u03bf", + "Disconnect": "\u0391\u03c0\u03bf\u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7", + "EnableDisplayMirroring": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03ba\u03b1\u03c4\u03bf\u03c0\u03c4\u03c1\u03b9\u03c3\u03bc\u03bf\u03cd \u03b5\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7\u03c2", + "HeaderPlayOn": "\u03a3\u03c5\u03bd\u03ad\u03c7\u03b9\u03c3\u03b5 \u03bd\u03b1 \u03c0\u03b1\u03af\u03b6\u03b5\u03b9\u03c2", + "Quality": "\u03a0\u03bf\u03b9\u03cc\u03c4\u03b7\u03c4\u03b1", + "Auto": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03bf", + "AndroidUnlockRestoreHelp": "\u0393\u03b9\u03b1 \u03bd\u03b1 \u03b5\u03c0\u03b1\u03bd\u03b1\u03c6\u03ad\u03c1\u03b5\u03c4\u03b5 \u03c4\u03b7\u03bd \u03c0\u03c1\u03bf\u03b7\u03b3\u03bf\u03cd\u03bc\u03b5\u03bd\u03b7 \u03b1\u03b3\u03bf\u03c1\u03ac \u03c3\u03b1\u03c2, \u03b2\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03c3\u03c5\u03bd\u03b4\u03b5\u03b8\u03b5\u03af \u03c3\u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03bc\u03b5 \u03c4\u03bf\u03bd \u03af\u03b4\u03b9\u03bf \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc Google (\u03ae Amazon) \u03c0\u03bf\u03c5 \u03c0\u03c1\u03b1\u03b3\u03bc\u03b1\u03c4\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b5 \u03b1\u03c1\u03c7\u03b9\u03ba\u03ac \u03c4\u03b7\u03bd \u03b1\u03b3\u03bf\u03c1\u03ac. \u0392\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03c4\u03bf \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b7\u03bc\u03b1 \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ce\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf \u03ba\u03b1\u03b9 \u03b4\u03b5\u03bd \u03c0\u03b5\u03c1\u03b9\u03bf\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9 \u03b1\u03c0\u03cc \u03ba\u03b1\u03bd\u03ad\u03bd\u03b1 \u03b3\u03bf\u03bd\u03b9\u03ba\u03cc \u03ad\u03bb\u03b5\u03b3\u03c7\u03bf \u03ba\u03b1\u03b9 \u03b2\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7 \u03c3\u03c4\u03bf \u03b4\u03b9\u03b1\u03b4\u03af\u03ba\u03c4\u03c5\u03bf. \u0398\u03b1 \u03c7\u03c1\u03b5\u03b9\u03b1\u03c3\u03c4\u03b5\u03af \u03bd\u03b1 \u03c4\u03bf \u03ba\u03ac\u03bd\u03b5\u03c4\u03b5 \u03bc\u03cc\u03bd\u03bf \u03bc\u03af\u03b1 \u03c6\u03bf\u03c1\u03ac \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03b5\u03c0\u03b1\u03bd\u03b1\u03c6\u03ad\u03c1\u03b5\u03c4\u03b5 \u03c4\u03b7\u03bd \u03c0\u03c1\u03bf\u03b7\u03b3\u03bf\u03cd\u03bc\u03b5\u03bd\u03b7 \u03b1\u03b3\u03bf\u03c1\u03ac \u03c3\u03b1\u03c2.", + "AspectRatio": "\u0391\u03c1\u03c7\u03b9\u03ba\u03cc\u03c2 \u03bb\u03cc\u03b3\u03bf\u03c2 \u03b4\u03b9\u03b1\u03c3\u03c4\u03ac\u03c3\u03b5\u03c9\u03bd:", + "Original": "\u03a0\u03c1\u03c9\u03c4\u03cc\u03c4\u03c5\u03c0\u03bf", + "Fill": "\u0393\u03ad\u03bc\u03b9\u03c3\u03bc\u03b1", + "BestFit": "\u03a4\u03b1\u03b9\u03c1\u03b9\u03ac\u03b6\u03b5\u03b9 \u03ba\u03b1\u03bb\u03cd\u03c4\u03b5\u03c1\u03b1", + "MessageNoServersAvailableToConnect": "\u0394\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03bd \u03b4\u03b9\u03b1\u03b8\u03ad\u03c3\u03b9\u03bc\u03bf\u03b9 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ad\u03c2 \u03b3\u03b9\u03b1 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7. \u0391\u03bd \u03ad\u03c7\u03b5\u03c4\u03b5 \u03c0\u03c1\u03bf\u03c3\u03ba\u03bb\u03b7\u03b8\u03b5\u03af \u03bd\u03b1 \u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03c4\u03b5\u03af\u03c4\u03b5 \u03ad\u03bd\u03b1 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae, \u03b2\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03c4\u03bf \u03b1\u03c0\u03bf\u03b4\u03b5\u03c7\u03b8\u03ae\u03ba\u03b1\u03c4\u03b5 \u03c0\u03b1\u03c1\u03b1\u03ba\u03ac\u03c4\u03c9 \u03ae \u03ba\u03ac\u03bd\u03bf\u03bd\u03c4\u03b1\u03c2 \u03ba\u03bb\u03b9\u03ba \u03c3\u03c4\u03bf \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf \u03c4\u03bf\u03c5 \u03bc\u03b7\u03bd\u03cd\u03bc\u03b1\u03c4\u03bf\u03c2 \u03b7\u03bb\u03b5\u03ba\u03c4\u03c1\u03bf\u03bd\u03b9\u03ba\u03bf\u03cd \u03c4\u03b1\u03c7\u03c5\u03b4\u03c1\u03bf\u03bc\u03b5\u03af\u03bf\u03c5.", + "MessagePlayAccessRestricted": "\u0397 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03b1\u03c5\u03c4\u03bf\u03cd \u03c4\u03bf\u03c5 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b1\u03c5\u03c4\u03ae \u03c4\u03b7 \u03c3\u03c4\u03b9\u03b3\u03bc\u03ae \u03c0\u03b5\u03c1\u03b9\u03bf\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03b7. \u0395\u03c0\u03b9\u03ba\u03bf\u03b9\u03bd\u03c9\u03bd\u03ae\u03c3\u03c4\u03b5 \u03bc\u03b5 \u03c4\u03bf\u03bd \u03b4\u03b9\u03b1\u03c7\u03b5\u03b9\u03c1\u03b9\u03c3\u03c4\u03ae \u03c4\u03bf\u03c5 Emby Server \u03b3\u03b9\u03b1 \u03c0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b5\u03c2 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2.", + "Accept": "\u0391\u03c0\u03bf\u03b4\u03bf\u03c7\u03ae", + "Reject": "\u0391\u03c0\u03cc\u03c1\u03b9\u03c8\u03b7", + "Connect": "\u03a3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7", + "HeaderMyMedia": "\u03a4\u03b1 \u03a0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03b1 \u03bc\u03bf\u03c5", + "HeaderMyMediaSmall": "\u03a4\u03b1 \u03a0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03b1 \u03bc\u03bf\u03c5 (\u03bc\u03b9\u03ba\u03c1\u03ac)", + "LatestFromLibrary": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 {0}", + "ContinueWatching": "\u03a3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03c4\u03b5 \u03bd\u03b1 \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03b5\u03af\u03c4\u03b5", + "HeaderLatestChannelMedia": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03ba\u03b1\u03bd\u03b1\u03bb\u03b9\u03bf\u03cd", + "HeaderContinueWatching": "\u03a3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03cd\u03b8\u03b7\u03c3\u03b7", + "HeaderContinueListening": "\u03a3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b1\u03ba\u03c1\u03cc\u03b1\u03c3\u03b7", + "HeaderActiveRecordings": "\u0395\u03bd\u03b5\u03c1\u03b3\u03ad\u03c2 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ad\u03c2", + "HeaderLatestRecordings": "\u03c4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b5\u03c2 \u03b7\u03c7\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c3\u03b5\u03b9\u03c2", + "LabelSyncTo": "\u03a3\u03c5\u03b3\u03c7\u03c1\u03bf\u03bd\u03b9\u03c3\u03bc\u03cc\u03c2 \u03c3\u03b5:", + "LabelConvertTo": "\u039c\u03b5\u03c4\u03b1\u03c4\u03c1\u03bf\u03c0\u03ae \u03c3\u03b5:", + "Next": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf", + "LabelSource": "\u03a0\u03b7\u03b3\u03ae:", + "LabelVersion": "\u0388\u03ba\u03b4\u03bf\u03c3\u03b7:", + "AllLanguages": "\u038c\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b5\u03c2", + "Previous": "\u03a0\u03c1\u03bf\u03b7\u03b3\u03bf\u03cd\u03bc\u03b5\u03bd\u03bf", + "HeaderNextUp": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf \u03b3\u03b9\u03b1 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae", + "HeaderLatestFrom": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 {0}", + "LabelHomeScreenSectionValue": "\u0391\u03c1\u03c7\u03b9\u03ba\u03ae \u03bf\u03b8\u03cc\u03bd\u03b7 {0}:", + "SettingsSaved": "\u039f\u03b9 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03cd\u03c4\u03b7\u03ba\u03b1\u03bd", + "None": "\u039a\u03b1\u03bd\u03ad\u03bd\u03b1", + "More": "\u03a0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b1 ", + "Up": "\u0395\u03c0\u03ac\u03bd\u03c9", + "Down": "\u039a\u03ac\u03c4\u03c9", + "Home": "\u0391\u03c1\u03c7\u03b9\u03ba\u03ae", + "Favorites": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1", + "HeaderHomeScreen": "\u0391\u03c1\u03c7\u03b9\u03ba\u03ae \u03bf\u03b8\u03cc\u03bd\u03b7", + "HeaderLatestChannelItems": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03ba\u03b1\u03bd\u03b1\u03bb\u03b9\u03bf\u03cd", + "HeaderLibraryOrder": "\u0394\u03b9\u03ac\u03c4\u03b1\u03be\u03b7 \u0392\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7\u03c2", + "HideWatchedContentFromLatestMedia": "\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03c0\u03c1\u03bf\u03b2\u03bb\u03b7\u03b8\u03ad\u03bd\u03c4\u03c9\u03bd \u03b1\u03c0\u03cc \u03c4\u03b1 \u03c0\u03c1\u03cc\u03c3\u03c6\u03b1\u03c4\u03b1 \u03bc\u03ad\u03c3\u03b1", + "HeaderOnNow": "\u03a4\u03ce\u03c1\u03b1", + "HeaderPlaybackError": "\u03a3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2", + "PlaybackErrorNotAllowed": "\u0394\u03b5\u03bd \u03b5\u03af\u03c3\u03c4\u03b5 \u03b5\u03c0\u03af \u03c4\u03bf\u03c5 \u03c0\u03b1\u03c1\u03cc\u03bd\u03c4\u03bf\u03c2 \u03b5\u03be\u03bf\u03c5\u03c3\u03b9\u03bf\u03b4\u03bf\u03c4\u03b7\u03bc\u03ad\u03bd\u03bf\u03c2 \u03bd\u03b1 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03ac\u03b3\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc \u03c4\u03bf \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf. \u0395\u03c0\u03b9\u03ba\u03bf\u03b9\u03bd\u03c9\u03bd\u03ae\u03c3\u03c4\u03b5 \u03bc\u03b5 \u03c4\u03bf \u03b4\u03b9\u03b1\u03c7\u03b5\u03b9\u03c1\u03b9\u03c3\u03c4\u03ae \u03c4\u03bf\u03c5 \u03c3\u03c5\u03c3\u03c4\u03ae\u03bc\u03b1\u03c4\u03cc\u03c2 \u03c3\u03b1\u03c2 \u03b3\u03b9\u03b1 \u03bb\u03b5\u03c0\u03c4\u03bf\u03bc\u03ad\u03c1\u03b5\u03b9\u03b5\u03c2.", + "PlaybackErrorNoCompatibleStream": "\u0394\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03bd \u03b5\u03c0\u03af \u03c4\u03bf\u03c5 \u03c0\u03b1\u03c1\u03cc\u03bd\u03c4\u03bf\u03c2 \u03b4\u03b9\u03b1\u03b8\u03ad\u03c3\u03b9\u03bc\u03b5\u03c2 \u03c3\u03c5\u03bc\u03b2\u03b1\u03c4\u03ad\u03c2 \u03c1\u03bf\u03ad\u03c2. \u0394\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03c4\u03b5 \u03be\u03b1\u03bd\u03ac \u03b1\u03c1\u03b3\u03cc\u03c4\u03b5\u03c1\u03b1 \u03ae \u03b5\u03c0\u03b9\u03ba\u03bf\u03b9\u03bd\u03c9\u03bd\u03ae\u03c3\u03c4\u03b5 \u03bc\u03b5 \u03c4\u03bf\u03bd \u03b4\u03b9\u03b1\u03c7\u03b5\u03b9\u03c1\u03b9\u03c3\u03c4\u03ae \u03c4\u03bf\u03c5 \u03c3\u03c5\u03c3\u03c4\u03ae\u03bc\u03b1\u03c4\u03bf\u03c2 \u03b3\u03b9\u03b1 \u03bb\u03b5\u03c0\u03c4\u03bf\u03bc\u03ad\u03c1\u03b5\u03b9\u03b5\u03c2.", + "PlaybackErrorPlaceHolder": "\u0395\u03b9\u03c3\u03b1\u03b3\u03ac\u03b3\u03b5\u03c4\u03b5 \u03c4\u03bf\u03bd \u03b4\u03af\u03c3\u03ba\u03bf \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03c0\u03b1\u03af\u03be\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc \u03c4\u03bf \u03b2\u03af\u03bd\u03c4\u03b5\u03bf.", + "Guide": "\u039f\u03b4\u03b7\u03b3\u03cc\u03c2", + "Suggestions": "\u03a0\u03c1\u03bf\u03c4\u03ac\u03c3\u03b5\u03b9\u03c2", + "HeaderFavoriteCollections": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b5\u03c2 \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ad\u03c2", + "HeaderFavoritePlaylists": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b5\u03c2 \u039b\u03af\u03c3\u03c4\u03b5\u03c2 \u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2", + "Collections": "\u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ad\u03c2", + "LabelSelectFolderGroups": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b7 \u03bf\u03bc\u03b1\u03b4\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5 \u03b1\u03c0\u03cc \u03c4\u03bf\u03c5\u03c2 \u03b1\u03ba\u03cc\u03bb\u03bf\u03c5\u03b8\u03bf\u03c5\u03c2 \u03c6\u03b1\u03ba\u03ad\u03bb\u03bf\u03c5\u03c2 \u03c3\u03b5 \u03c0\u03c1\u03bf\u03b2\u03bf\u03bb\u03ad\u03c2 \u03cc\u03c0\u03c9\u03c2 \u03c4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2, \u03bc\u03bf\u03c5\u03c3\u03b9\u03ba\u03ae \u03ba\u03b1\u03b9 \u03c4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7:", + "LabelSelectFolderGroupsHelp": "\u039f\u03b9 \u03c6\u03ac\u03ba\u03b5\u03bb\u03bf\u03b9 \u03c0\u03bf\u03c5 \u03b4\u03b5\u03bd \u03ad\u03c7\u03bf\u03c5\u03bd \u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03b5\u03af \u03b8\u03b1 \u03b5\u03bc\u03c6\u03b1\u03bd\u03af\u03b6\u03bf\u03bd\u03c4\u03b1\u03b9 \u03b1\u03c0\u03cc \u03bc\u03cc\u03bd\u03bf\u03b9 \u03c4\u03bf\u03c5\u03c2 \u03c3\u03c4\u03b7 \u03b4\u03b9\u03ba\u03ae \u03c4\u03bf\u03c5\u03c2 \u03ac\u03c0\u03bf\u03c8\u03b7.", + "Folders": "\u03a6\u03ac\u03ba\u03b5\u03bb\u03bf\u03b9", + "DisplayInOtherHomeScreenSections": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c3\u03c4\u03b1 \u03c4\u03bc\u03ae\u03bc\u03b1\u03c4\u03b1 \u03c4\u03b7\u03c2 \u03b1\u03c1\u03c7\u03b9\u03ba\u03ae\u03c2 \u03bf\u03b8\u03cc\u03bd\u03b7\u03c2, \u03cc\u03c0\u03c9\u03c2 \u03c4\u03b1 \u03c0\u03b9\u03bf \u03c0\u03c1\u03cc\u03c3\u03c6\u03b1\u03c4\u03b1 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03b1 \u03ba\u03b1\u03b9 \u03c3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03c4\u03b5 \u03bd\u03b1 \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03b5\u03af\u03c4\u03b5", + "DisplayInMyMedia": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c3\u03c4\u03b7\u03bd \u03b1\u03c1\u03c7\u03b9\u03ba\u03ae \u03bf\u03b8\u03cc\u03bd\u03b7", + "Shows": "\u03a3\u03b5\u03b9\u03c1\u03ad\u03c2", + "HeaderLibraryFolders": "\u03a6\u03ac\u03ba\u03b5\u03bb\u03bf\u03c2 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03b7\u03ba\u03ce\u03bd", + "HeaderTermsOfPurchase": "\u038c\u03c1\u03bf\u03b9 \u03b1\u03b3\u03bf\u03c1\u03ac\u03c2", + "PrivacyPolicy": "\u03a0\u03c1\u03bf\u03c3\u03c9\u03c0\u03b9\u03ba\u03ac \u0394\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03b1", + "TermsOfUse": "\u038c\u03c1\u03bf\u03b9 \u03a7\u03c1\u03ae\u03c3\u03b7\u03c2", + "RepeatMode": "\u039b\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03b5\u03c0\u03b1\u03bd\u03ac\u03bb\u03b7\u03c8\u03b7\u03c2", + "RepeatOne": "\u0395\u03c0\u03b1\u03bd\u03b1\u03bb\u03ac\u03b2\u03b5\u03c4\u03b5 \u03ad\u03bd\u03b1", + "RepeatAll": "\u0395\u03c0\u03b1\u03bd\u03ac\u03bb\u03b7\u03c8\u03b7 \u03cc\u03bb\u03c9\u03bd", + "LabelDefaultScreen": "\u03a0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03bc\u03ad\u03bd\u03b7 \u03bf\u03b8\u03cc\u03bd\u03b7:", + "ConfirmEndPlayerSession": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03ba\u03bb\u03b5\u03af\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf\u03bd Emby \u03c3\u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae;", + "Yes": "\u039d\u03b1\u03b9", + "No": "\u039f\u03c7\u03b9", + "LiveTV": "\u0396\u03a9\u039d\u03a4\u0391\u039d\u0397 \u03a4\u0397\u039b\u0395\u038c\u03a1\u0391\u03a3\u0397", + "Schedule": "\u03a0\u03c1\u03cc\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1", + "Recordings": "\u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ad\u03c2", + "MarkWatched": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03c7\u03b8\u03ad\u03bd\u03c4\u03b1", + "ScanForNewAndUpdatedFiles": "\u03a3\u03ac\u03c1\u03c9\u03c3\u03b7 \u03b3\u03b9\u03b1 \u03bd\u03ad\u03b1 \u03ba\u03b1\u03b9 \u03b5\u03bd\u03b7\u03bc\u03b5\u03c1\u03c9\u03bc\u03ad\u03bd\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03b1", + "DirectStreamHelp1": "\u03c4\u03bf \u03bc\u03ad\u03c3\u03bf \u03b5\u03af\u03bd\u03b1\u03b9 \u03c3\u03c5\u03bc\u03b2\u03b1\u03c4\u03cc \u03bc\u03b5 \u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03c3\u03b5 \u03c3\u03c7\u03ad\u03c3\u03b7 \u03bc\u03b5 \u03c4\u03b7\u03bd \u03b1\u03bd\u03ac\u03bb\u03c5\u03c3\u03b7 \u03ba\u03b1\u03b9 \u03c4\u03bf\u03bd \u03c4\u03cd\u03c0\u03bf \u03bc\u03ad\u03c3\u03bf\u03c5 (H.264, AC3 \u03ba.\u03bb\u03c0.), \u03b1\u03bb\u03bb\u03ac \u03b2\u03c1\u03af\u03c3\u03ba\u03b5\u03c4\u03b1\u03b9 \u03c3\u03b5 \u03bc\u03b7 \u03c3\u03c5\u03bc\u03b2\u03b1\u03c4\u03cc \u03c0\u03b5\u03c1\u03b9\u03ad\u03ba\u03c4\u03b7 \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd (.mkv, .avi, .wmv, \u03ba.\u03bb\u03c0.). \u03a4\u03bf \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b8\u03b1 \u03b1\u03bd\u03b1\u03c3\u03c5\u03b3\u03ba\u03c1\u03bf\u03c4\u03b7\u03b8\u03b5\u03af \u03b5\u03ba \u03bd\u03ad\u03bf\u03c5, \u03c0\u03c1\u03b9\u03bd \u03bc\u03b5\u03c4\u03b1\u03c6\u03b5\u03c1\u03b8\u03b5\u03af \u03c3\u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae.", + "DirectStreamHelp2": "\u0397 \u03ac\u03bc\u03b5\u03c3\u03b7 \u03c1\u03bf\u03ae \u03b5\u03bd\u03cc\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b5\u03af \u03b5\u03bb\u03ac\u03c7\u03b9\u03c3\u03c4\u03b7 \u03b9\u03c3\u03c7\u03cd \u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1\u03c2 \u03c7\u03c9\u03c1\u03af\u03c2 \u03b1\u03c0\u03ce\u03bb\u03b5\u03b9\u03b1 \u03c4\u03b7\u03c2 \u03c0\u03bf\u03b9\u03cc\u03c4\u03b7\u03c4\u03b1\u03c2 \u03c4\u03bf\u03c5 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf.", + "MediaIsBeingConverted": "\u03a4\u03bf \u03bc\u03ad\u03c3\u03bf \u03bc\u03b5\u03c4\u03b1\u03c4\u03c1\u03ad\u03c0\u03b5\u03c4\u03b1\u03b9 \u03c3\u03b5 \u03bc\u03bf\u03c1\u03c6\u03ae \u03c0\u03bf\u03c5 \u03b5\u03af\u03bd\u03b1\u03b9 \u03c3\u03c5\u03bc\u03b2\u03b1\u03c4\u03ae \u03bc\u03b5 \u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03c0\u03bf\u03c5 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03ac\u03b3\u03b5\u03b9 \u03c4\u03b1 \u03bc\u03ad\u03c3\u03b1.", + "StatsForNerds": "\u03a3\u03c4\u03b1\u03c4\u03b9\u03c3\u03c4\u03b9\u03ba\u03ac \u03b3\u03b9\u03b1 \u03ba\u03bf\u03c1\u03af\u03c4\u03c3\u03b9\u03b1", + "LabelReasonForTranscoding": "\u039b\u03cc\u03b3\u03bf\u03c2 \u03b3\u03b9\u03b1 \u03c4\u03b7\u03bd \u039a\u03c9\u03b4\u03b9\u03ba\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7:", + "DirectPlaying": "\u0391\u03c0\u03b5\u03c5\u03b8\u03b5\u03af\u03b1\u03c2 \u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae", + "DirectStreaming": "\u0391\u03c0\u03b5\u03c5\u03b8\u03b5\u03af\u03b1\u03c2 \u0391\u03bd\u03b1\u03bc\u03b5\u03c4\u03ac\u03b4\u03bf\u03c3\u03b7", + "Transcoding": "\u039a\u03c9\u03b4\u03b9\u03ba\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7", + "ContainerBitrateExceedsLimit": "\u03a4\u03bf bitrate \u03bc\u03ad\u03c3\u03c9\u03bd \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd \u03c5\u03c0\u03b5\u03c1\u03b2\u03b1\u03af\u03bd\u03b5\u03b9 \u03c4\u03bf \u03cc\u03c1\u03b9\u03bf.", + "VideoCodecNotSupported": "\u039f \u03ba\u03c9\u03b4\u03b9\u03ba\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03ae\u03c2 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "AudioCodecNotSupported": "\u039f \u03ba\u03c9\u03b4\u03b9\u03ba\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03ae\u03c2 \u03ae\u03c7\u03bf\u03c5 \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "SubtitleCodecNotSupported": "\u0397 \u03bc\u03bf\u03c1\u03c6\u03ae \u03c5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "DirectPlayError": "\u03a3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03ac\u03bc\u03b5\u03c3\u03b7\u03c2 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2", + "ContainerNotSupported": "\u03a4\u03bf \u03ba\u03bf\u03bd\u03c4\u03ad\u03b9\u03bd\u03b5\u03c1 \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "VideoLevelNotSupported": "\u03a4\u03bf \u03b5\u03c0\u03af\u03c0\u03b5\u03b4\u03bf \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "AudioBitrateNotSupported": "\u03a4\u03bf bitrate \u03ae\u03c7\u03bf\u03c5 \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "AudioChannelsNotSupported": "\u03a4\u03b1 \u03ba\u03b1\u03bd\u03ac\u03bb\u03b9\u03b1 \u03ae\u03c7\u03bf\u03c5 \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03bf\u03bd\u03c4\u03b1\u03b9", + "VideoResolutionNotSupported": "\u0397 \u03b1\u03bd\u03ac\u03bb\u03c5\u03c3\u03b7 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "AudioProfileNotSupported": "\u03a4\u03bf \u03c0\u03c1\u03bf\u03c6\u03af\u03bb \u03ae\u03c7\u03bf\u03c5 \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "AudioSampleRateNotSupported": "\u0394\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9 \u03c4\u03bf \u03c0\u03bf\u03c3\u03bf\u03c3\u03c4\u03cc \u03b4\u03b5\u03b9\u03b3\u03bc\u03b1\u03c4\u03bf\u03bb\u03b7\u03c8\u03af\u03b1\u03c2 \u03ae\u03c7\u03bf\u03c5", + "AnamorphicVideoNotSupported": "\u03a4\u03bf \u03b1\u03bd\u03b1\u03bc\u03bf\u03c1\u03c6\u03c9\u03c4\u03b9\u03ba\u03cc \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "InterlacedVideoNotSupported": "\u0394\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03b9\u03b6\u03cc\u03bc\u03b5\u03bd\u03bf \u03c4\u03bf \u03c0\u03b1\u03c1\u03b5\u03bc\u03b2\u03b1\u03bb\u03bb\u03cc\u03bc\u03b5\u03bd\u03bf \u03b2\u03af\u03bd\u03c4\u03b5\u03bf", + "SecondaryAudioNotSupported": "\u0397 \u03b5\u03bd\u03b1\u03bb\u03bb\u03b1\u03b3\u03ae \u03c4\u03b7\u03c2 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03ae\u03c7\u03bf\u03c5 \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "ErrorRemovingEmbyConnectAccount": "\u03a0\u03b1\u03c1\u03bf\u03c5\u03c3\u03b9\u03ac\u03c3\u03c4\u03b7\u03ba\u03b5 \u03ad\u03bd\u03b1 \u03c3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03ba\u03b1\u03c4\u03ac\u03c1\u03b3\u03b7\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03bf\u03cd Emby Connect. \u0392\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03bc\u03b9\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7 \u03c3\u03c4\u03bf Internet \u03ba\u03b1\u03b9 \u03c0\u03c1\u03bf\u03c3\u03c0\u03b1\u03b8\u03ae\u03c3\u03c4\u03b5 \u03be\u03b1\u03bd\u03ac.", + "HeaderEmbyAccountRemoved": "\u039f \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc\u03c2 Emby \u03ba\u03b1\u03c4\u03b1\u03c1\u03b3\u03ae\u03b8\u03b7\u03ba\u03b5", + "MessageEmbyAccontRemoved": "\u039f \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc\u03c2 Emby \u03ba\u03b1\u03c4\u03b1\u03c1\u03b3\u03ae\u03b8\u03b7\u03ba\u03b5 \u03b1\u03c0\u03cc \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf\u03bd \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7.", + "HeaderInvitationSent": "\u0397 \u03c0\u03c1\u03cc\u03c3\u03ba\u03bb\u03b7\u03c3\u03b7 \u03b1\u03c0\u03bf\u03c3\u03c4\u03ad\u03bb\u03bb\u03b5\u03c4\u03b1\u03b9", + "MessageInvitationSentToUser": "\u0388\u03bd\u03b1 \u03bc\u03ae\u03bd\u03c5\u03bc\u03b1 \u03b7\u03bb\u03b5\u03ba\u03c4\u03c1\u03bf\u03bd\u03b9\u03ba\u03bf\u03cd \u03c4\u03b1\u03c7\u03c5\u03b4\u03c1\u03bf\u03bc\u03b5\u03af\u03bf\u03c5 \u03ad\u03c7\u03b5\u03b9 \u03c3\u03c4\u03b1\u03bb\u03b5\u03af \u03c3\u03c4\u03bf {0}, \u03ba\u03b1\u03bb\u03ce\u03bd\u03c4\u03b1\u03c2 \u03c4\u03b1 \u03bd\u03b1 \u03b1\u03c0\u03bf\u03b4\u03b5\u03c7\u03b8\u03bf\u03cd\u03bd \u03c4\u03b7\u03bd \u03c0\u03c1\u03cc\u03c3\u03ba\u03bb\u03b7\u03c3\u03b7 \u03ba\u03bf\u03b9\u03bd\u03ae\u03c2 \u03c7\u03c1\u03ae\u03c3\u03b7\u03c2.", + "MessageInvitationSentToNewUser": "\u0388\u03b3\u03b9\u03bd\u03b5 \u03b1\u03c0\u03bf\u03c3\u03c4\u03bf\u03bb\u03ae \u03b5\u03bd\u03cc\u03c2 \u03bc\u03b7\u03bd\u03cd\u03bc\u03b1\u03c4\u03bf\u03c2 \u03b7\u03bb\u03b5\u03ba\u03c4\u03c1\u03bf\u03bd\u03b9\u03ba\u03bf\u03cd \u03c4\u03b1\u03c7\u03c5\u03b4\u03c1\u03bf\u03bc\u03b5\u03af\u03bf\u03c5 \u03c3\u03c4\u03bf {0}, \u03ba\u03b1\u03bb\u03ce\u03bd\u03c4\u03b1\u03c2 \u03c4\u03b1 \u03bd\u03b1 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03bf\u03cd\u03bd \u03c3\u03c4\u03bf Emby.", + "GuestUserNotFound": "\u039f \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2 \u03b4\u03b5\u03bd \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b5. \u0392\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03c4\u03bf \u03cc\u03bd\u03bf\u03bc\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03c3\u03c9\u03c3\u03c4\u03cc \u03ba\u03b1\u03b9 \u03b4\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03c4\u03b5 \u03be\u03b1\u03bd\u03ac \u03ae \u03b4\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03c4\u03b5 \u03bd\u03b1 \u03b5\u03b9\u03c3\u03ac\u03b3\u03b5\u03c4\u03b5 \u03c4\u03b7 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 \u03b7\u03bb\u03b5\u03ba\u03c4\u03c1\u03bf\u03bd\u03b9\u03ba\u03bf\u03cd \u03c4\u03b1\u03c7\u03c5\u03b4\u03c1\u03bf\u03bc\u03b5\u03af\u03bf\u03c5.", + "ErrorReachingEmbyConnect": "\u03a0\u03b1\u03c1\u03bf\u03c5\u03c3\u03b9\u03ac\u03c3\u03c4\u03b7\u03ba\u03b5 \u03ad\u03bd\u03b1 \u03c3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03c3\u03c4\u03bf \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae Emby Connect. \u0392\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03bc\u03b9\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7 \u03c3\u03c4\u03bf Internet \u03ba\u03b1\u03b9 \u03c0\u03c1\u03bf\u03c3\u03c0\u03b1\u03b8\u03ae\u03c3\u03c4\u03b5 \u03be\u03b1\u03bd\u03ac.", + "ErrorAddingEmbyConnectAccount1": "\u03a0\u03b1\u03c1\u03bf\u03c5\u03c3\u03b9\u03ac\u03c3\u03c4\u03b7\u03ba\u03b5 \u03ad\u03bd\u03b1 \u03c3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03c0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03c4\u03bf\u03c5 \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03bf\u03cd Emby Connect. \u0388\u03c7\u03b5\u03c4\u03b5 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03c3\u03b5\u03b9 \u03ad\u03bd\u03b1\u03bd \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc Emby; \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03b5\u03af\u03c4\u03b5 \u03c3\u03c4\u03bf {0}.", + "ErrorAddingEmbyConnectAccount2": "\u0391\u03bd \u03b5\u03be\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03b1\u03bd\u03c4\u03b9\u03bc\u03b5\u03c4\u03c9\u03c0\u03af\u03b6\u03b5\u03c4\u03b5 \u03ba\u03ac\u03c0\u03bf\u03b9\u03bf \u03c0\u03c1\u03cc\u03b2\u03bb\u03b7\u03bc\u03b1, \u03c3\u03c4\u03b5\u03af\u03bb\u03c4\u03b5 \u03ad\u03bd\u03b1 \u03bc\u03ae\u03bd\u03c5\u03bc\u03b1 \u03b7\u03bb\u03b5\u03ba\u03c4\u03c1\u03bf\u03bd\u03b9\u03ba\u03bf\u03cd \u03c4\u03b1\u03c7\u03c5\u03b4\u03c1\u03bf\u03bc\u03b5\u03af\u03bf\u03c5 \u03c3\u03c4\u03bf {0} \u03b1\u03c0\u03cc \u03c4\u03b7 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 \u03b7\u03bb\u03b5\u03ba\u03c4\u03c1\u03bf\u03bd\u03b9\u03ba\u03bf\u03cd \u03c4\u03b1\u03c7\u03c5\u03b4\u03c1\u03bf\u03bc\u03b5\u03af\u03bf\u03c5 \u03c0\u03bf\u03c5 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b5\u03af\u03c4\u03b1\u03b9 \u03bc\u03b5 \u03c4\u03bf \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc Emby.", + "ErrorAddingGuestAccount1": "\u03a0\u03b1\u03c1\u03bf\u03c5\u03c3\u03b9\u03ac\u03c3\u03c4\u03b7\u03ba\u03b5 \u03ad\u03bd\u03b1 \u03c3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03c0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03c4\u03bf\u03c5 \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03bf\u03cd Emby Connect. \u0388\u03c7\u03b5\u03b9 \u03bf \u03c6\u03b9\u03bb\u03bf\u03be\u03b5\u03bd\u03bf\u03cd\u03bc\u03b5\u03bd\u03bf\u03c2 \u03c3\u03b1\u03c2 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03c3\u03b5\u03b9 \u03ad\u03bd\u03b1\u03bd \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc Emby; \u039c\u03c0\u03bf\u03c1\u03bf\u03cd\u03bd \u03bd\u03b1 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03bf\u03cd\u03bd \u03c3\u03c4\u03bf {0}.", + "ErrorAddingGuestAccount2": "\u0395\u03ac\u03bd \u03b5\u03be\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03b1\u03bd\u03c4\u03b9\u03bc\u03b5\u03c4\u03c9\u03c0\u03af\u03b6\u03b5\u03c4\u03b5 \u03ba\u03ac\u03c0\u03bf\u03b9\u03bf \u03c0\u03c1\u03cc\u03b2\u03bb\u03b7\u03bc\u03b1, \u03c3\u03c4\u03b5\u03af\u03bb\u03c4\u03b5 \u03ad\u03bd\u03b1 \u03bc\u03ae\u03bd\u03c5\u03bc\u03b1 \u03b7\u03bb\u03b5\u03ba\u03c4\u03c1\u03bf\u03bd\u03b9\u03ba\u03bf\u03cd \u03c4\u03b1\u03c7\u03c5\u03b4\u03c1\u03bf\u03bc\u03b5\u03af\u03bf\u03c5 \u03c3\u03c4\u03bf {0} \u03ba\u03b1\u03b9 \u03c3\u03c5\u03bc\u03c0\u03b5\u03c1\u03b9\u03bb\u03ac\u03b2\u03b5\u03c4\u03b5 \u03c4\u03b7 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 \u03b7\u03bb\u03b5\u03ba\u03c4\u03c1\u03bf\u03bd\u03b9\u03ba\u03bf\u03cd \u03c4\u03b1\u03c7\u03c5\u03b4\u03c1\u03bf\u03bc\u03b5\u03af\u03bf\u03c5 \u03c3\u03b1\u03c2 \u03ba\u03b1\u03b8\u03ce\u03c2 \u03ba\u03b1\u03b9 \u03c4\u03b7 \u03b4\u03b9\u03ba\u03ae \u03c3\u03b1\u03c2.", + "MessageEmbyAccountAdded": "\u039f \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc\u03c2 Emby \u03ad\u03c7\u03b5\u03b9 \u03c0\u03c1\u03bf\u03c3\u03c4\u03b5\u03b8\u03b5\u03af \u03c3\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf\u03bd \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7.", + "MessagePendingEmbyAccountAdded": "\u039f \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc\u03c2 Emby \u03ad\u03c7\u03b5\u03b9 \u03c0\u03c1\u03bf\u03c3\u03c4\u03b5\u03b8\u03b5\u03af \u03c3\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf\u03bd \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7. \u0398\u03b1 \u03c3\u03c4\u03b1\u03bb\u03b5\u03af \u03ad\u03bd\u03b1 \u03bc\u03ae\u03bd\u03c5\u03bc\u03b1 \u03b7\u03bb\u03b5\u03ba\u03c4\u03c1\u03bf\u03bd\u03b9\u03ba\u03bf\u03cd \u03c4\u03b1\u03c7\u03c5\u03b4\u03c1\u03bf\u03bc\u03b5\u03af\u03bf\u03c5 \u03c3\u03c4\u03bf\u03bd \u03ba\u03ac\u03c4\u03bf\u03c7\u03bf \u03c4\u03bf\u03c5 \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03bf\u03cd. \u0397 \u03c0\u03c1\u03cc\u03c3\u03ba\u03bb\u03b7\u03c3\u03b7 \u03b8\u03b1 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03b5\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af \u03ba\u03ac\u03bd\u03bf\u03bd\u03c4\u03b1\u03c2 \u03ba\u03bb\u03b9\u03ba \u03c3\u03b5 \u03ad\u03bd\u03b1 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf \u03bc\u03ad\u03c3\u03b1 \u03c3\u03c4\u03bf email.", + "HeaderEmbyAccountAdded": "\u039b\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc\u03c2 Emby \u03a0\u03c1\u03bf\u03c3\u03c4\u03ad\u03b8\u03b7\u03ba\u03b5", + "LabelSubtitlePlaybackMode": "\u039b\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03c5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd:", + "ErrorDeletingItem": "\u03a0\u03b1\u03c1\u03bf\u03c5\u03c3\u03b9\u03ac\u03c3\u03c4\u03b7\u03ba\u03b5 \u03c3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7 \u03b4\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03c4\u03bf\u03c5 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf\u03c5 \u03b1\u03c0\u03cc \u03c4\u03bf\u03bd \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae Emby. \u0392\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03bf \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae\u03c2 Emby \u03ad\u03c7\u03b5\u03b9 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2 \u03c3\u03c4\u03bf \u03c6\u03ac\u03ba\u03b5\u03bb\u03bf \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd \u03ba\u03b1\u03b9 \u03c0\u03c1\u03bf\u03c3\u03c0\u03b1\u03b8\u03ae\u03c3\u03c4\u03b5 \u03be\u03b1\u03bd\u03ac.", + "NoSubtitles": "\u03a7\u03c9\u03c1\u03af\u03c2 \u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03c5\u03c2", + "Default": "\u03a0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae", + "Absolute": "\u0391\u03c0\u03cc\u03bb\u03c5\u03c4\u03bf", + "Smart": "\u0388\u03be\u03c5\u03c0\u03bd\u03bf", + "Small": "\u039c\u03b9\u03ba\u03c1\u03cc", + "Smaller": "\u039c\u03b9\u03ba\u03c1\u03cc\u03c4\u03b5\u03c1\u03bf", + "Medium": "\u039c\u03b5\u03c3\u03b1\u03af\u03bf", + "Large": "\u039c\u03b5\u03b3\u03ac\u03bb\u03bf", + "ExtraLarge": "\u03a0\u03bf\u03bb\u03cd \u039c\u03b5\u03b3\u03ac\u03bb\u03bf", + "OnlyForcedSubtitles": "\u039c\u03cc\u03bd\u03bf \u03b1\u03bd\u03b1\u03b3\u03ba\u03b1\u03c3\u03bc\u03ad\u03bd\u03bf\u03b9 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9", + "AlwaysPlaySubtitles": "\u03a0\u03ac\u03bd\u03c4\u03b1 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03a5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd", + "DefaultSubtitlesHelp": "\u039f\u03b9 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9 \u03c6\u03bf\u03c1\u03c4\u03ce\u03bd\u03bf\u03bd\u03c4\u03b1\u03b9 \u03bc\u03b5 \u03b2\u03ac\u03c3\u03b7 \u03c4\u03b9\u03c2 \u03c0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03bc\u03ad\u03bd\u03b5\u03c2 \u03ba\u03b1\u03b9 \u03b1\u03bd\u03b1\u03b3\u03ba\u03b1\u03c3\u03bc\u03ad\u03bd\u03b5\u03c2 \u03c3\u03b7\u03bc\u03b1\u03af\u03b5\u03c2 \u03c3\u03c4\u03b1 \u03b5\u03bd\u03c3\u03c9\u03bc\u03b1\u03c4\u03c9\u03bc\u03ad\u03bd\u03b1 \u03bc\u03b5\u03c4\u03b1\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03b1. \u039f\u03b9 \u03c0\u03c1\u03bf\u03c4\u03b9\u03bc\u03ae\u03c3\u03b5\u03b9\u03c2 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1\u03c2 \u03b5\u03be\u03b5\u03c4\u03ac\u03b6\u03bf\u03bd\u03c4\u03b1\u03b9 \u03cc\u03c4\u03b1\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03bd \u03c0\u03bf\u03bb\u03bb\u03ad\u03c2 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ad\u03c2.", + "SmartSubtitlesHelp": "\u039f\u03b9 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9 \u03c0\u03bf\u03c5 \u03c4\u03b1\u03b9\u03c1\u03b9\u03ac\u03b6\u03bf\u03c5\u03bd \u03bc\u03b5 \u03c4\u03b7\u03bd \u03c0\u03c1\u03bf\u03c4\u03af\u03bc\u03b7\u03c3\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1\u03c2 \u03b8\u03b1 \u03c6\u03bf\u03c1\u03c4\u03c9\u03b8\u03bf\u03cd\u03bd \u03cc\u03c4\u03b1\u03bd \u03bf \u03ae\u03c7\u03bf\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03c3\u03b5 \u03be\u03ad\u03bd\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1.", + "HeaderSubtitleSettings": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03a5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd", + "HeaderSubtitleAppearance": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd", + "OnlyForcedSubtitlesHelp": "\u039c\u03cc\u03bd\u03bf \u03bf\u03b9 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9 \u03c0\u03bf\u03c5 \u03ad\u03c7\u03bf\u03c5\u03bd \u03b5\u03c0\u03b9\u03c3\u03b7\u03bc\u03b1\u03bd\u03b8\u03b5\u03af \u03c9\u03c2 \u03b1\u03bd\u03b1\u03b3\u03ba\u03b1\u03c3\u03bc\u03ad\u03bd\u03bf\u03b9 \u03b8\u03b1 \u03c6\u03bf\u03c1\u03c4\u03c9\u03b8\u03bf\u03cd\u03bd.", + "AlwaysPlaySubtitlesHelp": "\u039f\u03b9 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9 \u03c0\u03bf\u03c5 \u03c4\u03b1\u03b9\u03c1\u03b9\u03ac\u03b6\u03bf\u03c5\u03bd \u03bc\u03b5 \u03c4\u03b9\u03c2 \u03c0\u03c1\u03bf\u03c4\u03b9\u03bc\u03ae\u03c3\u03b5\u03b9\u03c2 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1\u03c2 \u03b8\u03b1 \u03c6\u03bf\u03c1\u03c4\u03c9\u03b8\u03bf\u03cd\u03bd \u03b1\u03bd\u03b5\u03be\u03ac\u03c1\u03c4\u03b7\u03c4\u03b1 \u03b1\u03c0\u03cc \u03c4\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1 \u03c4\u03bf\u03c5 \u03ae\u03c7\u03bf\u03c5.", + "NoSubtitlesHelp": "\u039f\u03b9 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9 \u03b4\u03b5\u03bd \u03b8\u03b1 \u03c6\u03bf\u03c1\u03c4\u03c9\u03b8\u03bf\u03cd\u03bd \u03b1\u03c0\u03cc \u03c0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae.\u039c\u03c0\u03bf\u03c1\u03bf\u03cd\u03bd \u03b1\u03ba\u03cc\u03bc\u03b1 \u03bd\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03bf\u03cd\u03bd\u03c4\u03b1\u03b9 \u03c7\u03b5\u03b9\u03c1\u03bf\u03ba\u03af\u03bd\u03b7\u03c4\u03b1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae.", + "LabelPreferredSubtitleLanguage": "\u03a0\u03c1\u03bf\u03c4\u03b5\u03b9\u03bd\u03cc\u03bc\u03b5\u03bd\u03b7 \u0393\u03bb\u03ce\u03c3\u03c3\u03b1 \u03c5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd:", + "LabelTextSize": "\u039c\u03ad\u03b3\u03b5\u03b8\u03bf\u03c2 \u039a\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5:", + "TheseSettingsAffectSubtitlesOnThisDevice": "\u0391\u03c5\u03c4\u03ad\u03c2 \u03bf\u03b9 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03b5\u03c0\u03b7\u03c1\u03b5\u03ac\u03b6\u03bf\u03c5\u03bd \u03c4\u03bf\u03c5\u03c2 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03c5\u03c2 \u03b1\u03c5\u03c4\u03ae\u03c2 \u03c4\u03b7\u03c2 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae\u03c2", + "LabelDropShadow": "\u03a3\u03ba\u03af\u03b1\u03c3\u03b7:", + "LabelTextBackgroundColor": "\u03a7\u03c1\u03ce\u03bc\u03b1 \u03c6\u03cc\u03bd\u03c4\u03bf\u03c5 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5:", + "LabelWindowBackgroundColor": "\u03a7\u03c1\u03ce\u03bc\u03b1 \u03c6\u03cc\u03bd\u03c4\u03bf\u03c5 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5:", + "LabelFont": "\u0393\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03bf\u03c3\u03b5\u03b9\u03c1\u03ac: ", + "LabelTextColor": "\u03a7\u03c1\u03ce\u03bc\u03b1 \u039a\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5:", + "Raised": "\u0391\u03c5\u03be\u03ae\u03b8\u03b7\u03ba\u03b5", + "Depressed": "\u039c\u03b5\u03b9\u03ce\u03b8\u03b7\u03ba\u03b5", + "Uniform": "\u03bf\u03bc\u03bf\u03b5\u03b9\u03b4\u03ae\u03c2", + "DropShadow": "\u03a3\u03ba\u03af\u03b1\u03c3\u03b7", + "SmallCaps": "\u03bc\u03b9\u03ba\u03c1\u03ac \u03b3\u03c1\u03ac\u03bc\u03bc\u03b1\u03c4\u03b1", + "SubtitleAppearanceSettingsDisclaimer": "\u0391\u03c5\u03c4\u03ad\u03c2 \u03bf\u03b9 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03b4\u03b5\u03bd \u03b8\u03b1 \u03b9\u03c3\u03c7\u03cd\u03bf\u03c5\u03bd \u03b3\u03b9\u03b1 \u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03bf\u03cd\u03c2 \u03c5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03bf\u03c5\u03c2 (PGS, DVD, \u03ba.\u03bb\u03c0.) \u03ae \u03b3\u03b9\u03b1 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03c5\u03c2 \u03c0\u03bf\u03c5 \u03ad\u03c7\u03bf\u03c5\u03bd \u03b5\u03bd\u03c3\u03c9\u03bc\u03b1\u03c4\u03c9\u03bc\u03ad\u03bd\u03bf \u03c4\u03bf \u03b4\u03b9\u03ba\u03cc \u03c4\u03bf\u03c5\u03c2 \u03c3\u03c4\u03c5\u03bb (ASS \/ SSA).", + "LabelBurnSubtitles": "\u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03c9\u03bd:", + "OnlyImageFormats": "\u039c\u03cc\u03bd\u03bf \u03bc\u03bf\u03c1\u03c6\u03ad\u03c2 \u03b5\u03b9\u03ba\u03cc\u03bd\u03c9\u03bd (VOBSUB, PGS, SUB \/ IDX \u03ba.\u03bb\u03c0.)", + "Normal": "\u039a\u03b1\u03bd\u03bf\u03bd\u03b9\u03ba\u03cc\u03c2", + "BurnSubtitlesHelp": "\u039a\u03b1\u03b8\u03bf\u03c1\u03af\u03b6\u03b5\u03b9 \u03b1\u03bd \u03bf \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae\u03c2 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03b5\u03b3\u03b3\u03c1\u03ac\u03c8\u03b5\u03b9 \u03c3\u03c4\u03bf\u03c5\u03c2 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03c5\u03c2 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7 \u03bc\u03b5\u03c4\u03b1\u03c4\u03c1\u03bf\u03c0\u03ae \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b1\u03bd\u03ac\u03bb\u03bf\u03b3\u03b1 \u03bc\u03b5 \u03c4\u03b7 \u03bc\u03bf\u03c1\u03c6\u03ae \u03c4\u03c9\u03bd \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03c9\u03bd. \u0397 \u03b1\u03c0\u03bf\u03c6\u03c5\u03b3\u03ae \u03c4\u03b7\u03c2 \u03b5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2 \u03c3\u03c4\u03bf\u03c5\u03c2 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03c5\u03c2 \u03b8\u03b1 \u03b2\u03b5\u03bb\u03c4\u03b9\u03ce\u03c3\u03b5\u03b9 \u03c4\u03b7\u03bd \u03b1\u03c0\u03cc\u03b4\u03bf\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae. \u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b1 \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03b5\u03b3\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03bc\u03bf\u03c1\u03c6\u03ad\u03c2 \u03b2\u03b1\u03c3\u03b9\u03c3\u03bc\u03ad\u03bd\u03b5\u03c2 \u03c3\u03b5 \u03b5\u03b9\u03ba\u03cc\u03bd\u03b5\u03c2 (\u03c0.\u03c7. VOBSUB, PGS, SUB \/ IDX \u03ba.\u03bb\u03c0.) \u03ba\u03b1\u03b8\u03ce\u03c2 \u03ba\u03b1\u03b9 \u03bf\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03bf\u03c5\u03c2 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03c5\u03c2 ASS \/ SSA", + "AllComplexFormats": "\u038c\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03c3\u03cd\u03bd\u03b8\u03b5\u03c4\u03b5\u03c2 \u03bc\u03bf\u03c1\u03c6\u03ad\u03c2 (ASS, SSA, VOBSUB, PGS, SUB \/ IDX \u03ba.\u03bb\u03c0.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "\u0391\u03c5\u03c4\u03ad\u03c2 \u03bf\u03b9 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03b9\u03c3\u03c7\u03cd\u03bf\u03c5\u03bd \u03b5\u03c0\u03af\u03c3\u03b7\u03c2 \u03b3\u03b9\u03b1 \u03bf\u03c0\u03bf\u03b9\u03b1\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03c4\u03bf\u03c5 Chromecast \u03c0\u03bf\u03c5 \u03be\u03b5\u03ba\u03af\u03bd\u03b7\u03c3\u03b5 \u03b1\u03c0\u03cc \u03b1\u03c5\u03c4\u03ae\u03bd \u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae.", + "HeaderWaitingForWifi": "\u0391\u03bd\u03b1\u03bc\u03bf\u03bd\u03ae \u03b3\u03b9\u03b1 Wifi", + "WifiRequiredToDownload": "\u0391\u03c0\u03b1\u03b9\u03c4\u03b5\u03af\u03c4\u03b1\u03b9 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7 Wi-Fi \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03c3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b7 \u03bb\u03ae\u03c8\u03b7.", + "HeaderDownloadSettings": "\u039b\u03ae\u03c8\u03b7 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c9\u03bd", + "Hide": "\u039a\u03c1\u03cd\u03c8\u03b5", + "HeaderStartNow": "\u039e\u03b5\u03ba\u03af\u03bd\u03b1 \u03c4\u03ce\u03c1\u03b1", + "HeaderNextVideoPlayingInValue": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03b7 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03c3\u03b5 {0}", + "HeaderNextEpisodePlayingInValue": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03bf \u03c0\u03bf\u03c5 \u03b8\u03b1 \u03c0\u03b1\u03b9\u03c7\u03c4\u03b5\u03af \u03c3\u03b5 {0}", + "HeaderSecondsValue": "{0} \u03b4\u03b5\u03c5\u03c4\u03b5\u03c1\u03cc\u03bb\u03b5\u03c0\u03c4\u03b1", + "AudioBitDepthNotSupported": "\u03a4\u03bf \u03b2\u03ac\u03b8\u03bf\u03c2 bitrate \u03ae\u03c7\u03bf\u03c5 \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "VideoProfileNotSupported": "\u03a4\u03bf \u03c0\u03c1\u03bf\u03c6\u03af\u03bb \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "VideoFramerateNotSupported": "\u03a4\u03bf \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03ba\u03b1\u03c1\u03ad \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "VideoBitDepthNotSupported": "\u03a4\u03bf \u03b2\u03ac\u03b8\u03bf\u03c2 \u03c4\u03bf\u03c5 bit \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "RefFramesNotSupported": "\u039f \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc\u03c2 \u03c0\u03bb\u03b1\u03b9\u03c3\u03af\u03c9\u03bd \u03b1\u03bd\u03b1\u03c6\u03bf\u03c1\u03ac\u03c2 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9", + "ErrorConnectServerUnreachable": "\u03a0\u03b1\u03c1\u03bf\u03c5\u03c3\u03b9\u03ac\u03c3\u03c4\u03b7\u03ba\u03b5 \u03c3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03b5\u03ba\u03c4\u03ad\u03bb\u03b5\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03b6\u03b7\u03c4\u03bf\u03cd\u03bc\u03b5\u03bd\u03b7\u03c2 \u03b5\u03bd\u03ad\u03c1\u03b3\u03b5\u03b9\u03b1\u03c2. \u039f \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae\u03c2 \u03c3\u03b1\u03c2 \u03b4\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03b5\u03c0\u03b9\u03ba\u03bf\u03b9\u03bd\u03c9\u03bd\u03ae\u03c3\u03b5\u03b9 \u03bc\u03b5 \u03c4\u03bf \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae Emby Connect \u03c3\u03c4\u03bf {0}. \u0392\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03bf \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae\u03c2 \u03c3\u03b1\u03c2 \u03b4\u03b9\u03b1\u03b8\u03ad\u03c4\u03b5\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7 \u03c3\u03c4\u03bf \u03b4\u03b9\u03b1\u03b4\u03af\u03ba\u03c4\u03c5\u03bf \u03ba\u03b1\u03b9 \u03cc\u03c4\u03b9 \u03bf\u03b9 \u03b5\u03c0\u03b9\u03ba\u03bf\u03b9\u03bd\u03c9\u03bd\u03af\u03b5\u03c2 \u03b5\u03c0\u03b9\u03c4\u03c1\u03ad\u03c0\u03bf\u03bd\u03c4\u03b1\u03b9 \u03b1\u03c0\u03cc \u03bf\u03c0\u03bf\u03b9\u03bf\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03c4\u03b5\u03af\u03c7\u03bf\u03c2 \u03c0\u03c1\u03bf\u03c3\u03c4\u03b1\u03c3\u03af\u03b1\u03c2 \u03ae \u03bb\u03bf\u03b3\u03b9\u03c3\u03bc\u03b9\u03ba\u03cc \u03b1\u03c3\u03c6\u03b1\u03bb\u03b5\u03af\u03b1\u03c2 \u03c0\u03bf\u03c5 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03ae\u03c3\u03b5\u03b9.", + "StopRecording": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2", + "HeaderStopRecording": "\u0394\u03b9\u03b1\u03ba\u03bf\u03c0\u03ae \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2", + "ManageRecording": "\u0394\u03b9\u03b1\u03c7\u03b5\u03af\u03c1\u03b9\u03c3\u03b7 \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ce\u03bd", + "LabelDropImageHere": "\u039a\u03ac\u03bd\u03c4\u03b5 \u03ba\u03bb\u03b9\u03ba \u03b5\u03b4\u03ce, \u03ae \u03ba\u03ac\u03bd\u03c4\u03b5 \u03ba\u03bb\u03b9\u03ba \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03c0\u03b5\u03c1\u03b9\u03b7\u03b3\u03b7\u03b8\u03b5\u03af\u03c4\u03b5.", + "MessageFileReadError": "\u03a0\u03b1\u03c1\u03bf\u03c5\u03c3\u03b9\u03ac\u03c3\u03c4\u03b7\u03ba\u03b5 \u03c3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03b1\u03bd\u03ac\u03b3\u03bd\u03c9\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5. \u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03c0\u03c1\u03bf\u03c3\u03c0\u03ac\u03b8\u03b7\u03c3\u03b5 \u03be\u03b1\u03bd\u03ac.", + "Browse": "\u0391\u03bd\u03b1\u03b6\u03b7\u03c4\u03ae\u03c3\u03c4\u03b5", + "HeaderUploadImage": "\u0391\u03bd\u03b5\u03b2\u03ac\u03c3\u03c4\u03b5 \u03bd\u03ad\u03b1 \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1", + "HeaderAddUpdateImage": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \/ \u0395\u03bd\u03b7\u03bc\u03ad\u03c1\u03c9\u03c3\u03b7 \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2", + "LabelImageType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u0395\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2:", + "Upload": "\u0391\u03bd\u03b5\u03b2\u03ac\u03c3\u03c4\u03b5 ", + "Primary": "\u03a0\u03c1\u03c9\u03c4\u03b5\u03cd\u03bf\u03bd", + "Art": "\u03a4\u03ad\u03c7\u03bd\u03b7", + "Backdrop": "\u03a6\u03cc\u03bd\u03c4\u03bf", + "Banner": "\u03a0\u03b1\u03bd\u03cc", + "Box": "\u039a\u03bf\u03c5\u03c4\u03af", + "BoxRear": "Box (rear)", + "Disc": "\u0394\u03af\u03c3\u03ba\u03bf\u03c2", + "Logo": "\u03bb\u03bf\u03b3\u03cc\u03c4\u03c5\u03c0\u03bf", + "Menu": "\u039c\u03b5\u03bd\u03bf\u03cd", + "Screenshot": "\u03a3\u03c4\u03b9\u03b3\u03bc\u03b9\u03cc\u03c4\u03c5\u03c0\u03bf ", + "Thumb": "Thumb", + "ValueSeconds": "{0} \u03b4\u03b5\u03c5\u03c4\u03b5\u03c1\u03cc\u03bb\u03b5\u03c0\u03c4\u03b1", + "HeaderAudioSettings": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u0389\u03c7\u03bf\u03c5", + "LabelAudioLanguagePreference": "\u03a0\u03c1\u03bf\u03c4\u03b9\u03bc\u03ce\u03bc\u03b5\u03bd\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1 \u03ae\u03c7\u03bf\u03c5:", + "LabelPlayDefaultAudioTrack": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03c0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03bc\u03ad\u03bd\u03bf\u03c5 \u03ba\u03bf\u03bc\u03bc\u03b1\u03c4\u03b9\u03bf\u03cd \u03ae\u03c7\u03bf\u03c5 \u03b1\u03bd\u03b5\u03be\u03ac\u03c1\u03c4\u03b7\u03c4\u03b1 \u03b1\u03c0\u03cc \u03c4\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1", + "HeaderVideoQuality": "\u03a0\u03bf\u03b9\u03cc\u03c4\u03b7\u03c4\u03b1 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf", + "CinemaModeConfigurationHelp": "\u0397 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u039a\u03b9\u03bd\u03b7\u03bc\u03b1\u03c4\u03bf\u03b3\u03c1\u03ac\u03c6\u03bf\u03c5 \u03c3\u03ac\u03c2 \u03c0\u03c1\u03bf\u03c3\u03c6\u03ad\u03c1\u03b5\u03b9 \u03c4\u03b7\u03bd \u03c0\u03c1\u03b1\u03b3\u03bc\u03b1\u03c4\u03b9\u03ba\u03ae \u03ba\u03b9\u03bd\u03b7\u03bc\u03b1\u03c4\u03bf\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03ae \u03b5\u03bc\u03c0\u03b5\u03b9\u03c1\u03af\u03b1 \u03bc\u03b5 \u03c4\u03c1\u03ad\u03b9\u03bb\u03b5\u03c1 \u03ba\u03b1\u03b9 \u03c0\u03c1\u03bf\u03c3\u03b1\u03c1\u03bc\u03bf\u03c3\u03bc\u03ad\u03bd\u03b1 intros \u03c0\u03c1\u03b9\u03bd \u03b1\u03c0\u03cc \u03c4\u03b7 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1.", + "EnableNextVideoInfoOverlay": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b9\u03c2 \u03b5\u03c0\u03cc\u03bc\u03b5\u03bd\u03b5\u03c2 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae", + "EnableNextVideoInfoOverlayHelp": "\u03a3\u03c4\u03bf \u03c4\u03ad\u03bb\u03bf\u03c2 \u03b5\u03bd\u03cc\u03c2 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf, \u03b5\u03bc\u03c6\u03b1\u03bd\u03af\u03c3\u03c4\u03b5 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03c3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ac \u03bc\u03b5 \u03c4\u03bf \u03b5\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03c0\u03bf\u03c5 \u03b5\u03bc\u03c6\u03b1\u03bd\u03af\u03b6\u03b5\u03c4\u03b1\u03b9 \u03c3\u03c4\u03b7\u03bd \u03c4\u03c1\u03ad\u03c7\u03bf\u03c5\u03c3\u03b1 \u03bb\u03af\u03c3\u03c4\u03b1 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2.", + "PlayNextEpisodeAutomatically": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03c4\u03bf\u03c5 \u03b5\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf\u03c5 \u03b5\u03c0\u03b5\u03b9\u03c3\u03bf\u03b4\u03af\u03bf\u03c5 \u03b1\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b1", + "LabelMaxChromecastBitrate": "\u03a1\u03bf\u03ae \u03c0\u03bf\u03b9\u03cc\u03c4\u03b7\u03c4\u03b1\u03c2 Chromecast:", + "LabelSkipBackLength": "\u03a0\u03b1\u03c1\u03ac\u03bb\u03b5\u03b9\u03c8\u03b7 \u03c0\u03af\u03c3\u03c9 \u03bc\u03ae\u03ba\u03bf\u03c5\u03c2:", + "LabelSkipForwardLength": "\u03a0\u03b1\u03c1\u03ac\u03bb\u03b5\u03b9\u03c8\u03b7 \u03c0\u03c1\u03bf\u03c2 \u03c4\u03b1 \u03b5\u03bc\u03c0\u03c1\u03cc\u03c2:", + "EnableCinemaMode": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b7 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u039a\u03b9\u03bd\u03b7\u03bc\u03b1\u03c4\u03bf\u03b3\u03c1\u03ac\u03c6\u03bf\u03c2", + "LabelInternetQuality": "\u03a0\u03bf\u03b9\u03cc\u03c4\u03b7\u03c4\u03b1 Internet:", + "HeaderMusicQuality": "\u03a0\u03bf\u03b9\u03cc\u03c4\u03b7\u03c4\u03b1 \u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ae\u03c2", + "LabelHomeNetworkQuality": "\u03a0\u03bf\u03b9\u03cc\u03c4\u03b7\u03c4\u03b1 \u03bf\u03b9\u03ba\u03b9\u03b1\u03ba\u03bf\u03cd \u03b4\u03b9\u03ba\u03c4\u03cd\u03bf\u03c5:", + "HeaderLatestMedia": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03a0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03b1", + "HeaderRestartingEmbyServer": "\u0395\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae", + "RestartPleaseWaitMessage": "\u03a0\u03b5\u03c1\u03b9\u03bc\u03ad\u03bd\u03b5\u03c4\u03b5 \u03bc\u03ad\u03c7\u03c1\u03b9 \u03bf \u03c4\u03b5\u03c1\u03bc\u03b1\u03c4\u03b9\u03ba\u03cc\u03c2 \u03c3\u03c4\u03b1\u03b8\u03bc\u03cc\u03c2 Emby \u03bd\u03b1 \u03c4\u03b5\u03c1\u03bc\u03b1\u03c4\u03b9\u03c3\u03c4\u03b5\u03af \u03ba\u03b1\u03b9 \u03bd\u03b1 \u03b5\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03b9\u03bd\u03ae\u03c3\u03b5\u03b9. \u0391\u03c5\u03c4\u03cc \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03b4\u03b9\u03b1\u03c1\u03ba\u03ad\u03c3\u03b5\u03b9 \u03ad\u03bd\u03b1 \u03bb\u03b5\u03c0\u03c4\u03cc \u03ae \u03b4\u03cd\u03bf.", + "PlayNext": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03b7 \u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae", + "AllowSeasonalThemes": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03b5\u03c0\u03bf\u03c7\u03b9\u03b1\u03ba\u03ce\u03bd \u03b8\u03b5\u03bc\u03ac\u03c4\u03c9\u03bd", + "AllowSeasonalThemesHelp": "\u0395\u03ac\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf, \u03c4\u03b1 \u03b5\u03c0\u03bf\u03c7\u03b9\u03b1\u03ba\u03ac \u03b8\u03ad\u03bc\u03b1\u03c4\u03b1 \u03ba\u03b1\u03c4\u03ac \u03ba\u03b1\u03b9\u03c1\u03bf\u03cd\u03c2 \u03b8\u03b1 \u03b1\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03ae\u03c3\u03bf\u03c5\u03bd \u03c4\u03b7 \u03c1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7 \u03b8\u03ad\u03bc\u03b1\u03c4\u03bf\u03c2.", + "AutoBasedOnLanguageSetting": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b1 (\u03bc\u03b5 \u03b2\u03ac\u03c3\u03b7 \u03c4\u03b7 \u03c1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1\u03c2)", + "LabelDateTimeLocale": "\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u03c4\u03bf\u03c0\u03b9\u03ba\u03ae \u03ce\u03c1\u03b1:", + "DirectorValue": "\u03a3\u03ba\u03b7\u03bd\u03bf\u03b8\u03ad\u03c4\u03b7\u03c2: {0}", + "DirectorsValue": "\u03a3\u03ba\u03b7\u03bd\u03bf\u03b8\u03ad\u03c4\u03b5\u03c2: {0}", + "GenreValue": "\u0395\u03af\u03b4\u03bf\u03c2: {0}", + "GenresValue": "\u0395\u03af\u03b4\u03b7: {0}", + "LinksValue": "\u03a3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03b9: {0}", + "TagsValue": "\u0395\u03c4\u03b9\u03ba\u03ad\u03c4\u03b5\u03c2: {0}", + "LabelAudio": "\u0389\u03c7\u03bf\u03c2:", + "LabelVideo": "\u0392\u03af\u03bd\u03c4\u03b5\u03bf:", + "LabelSubtitles": "\u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9:", + "Off": "\u039a\u03bb\u03b5\u03b9\u03c3\u03c4\u03cc", + "ShowTitle": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c4\u03af\u03c4\u03bb\u03bf\u03c5", + "ShowYear": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03ad\u03c4\u03bf\u03c5\u03c2", + "Filters": "\u03a6\u03af\u03bb\u03c4\u03c1\u03b1", + "Unplayed": "\u0394\u03b5\u03bd \u03c0\u03b1\u03af\u03c7\u03b8\u03b7\u03ba\u03b5", + "LabelTVHomeScreen": "\u0391\u03c1\u03c7\u03b9\u03ba\u03ae \u03bf\u03b8\u03cc\u03bd\u03b7 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1\u03c2 \u03c4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7\u03c2:", + "Horizontal": "\u039f\u03c1\u03b9\u03b6\u03cc\u03bd\u03c4\u03b9\u03b1", + "Vertical": "\u039a\u03ac\u03b8\u03b5\u03c4\u03b1", + "GroupBySeries": "\u039f\u03bc\u03b1\u03b4\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03ba\u03b1\u03c4\u03ac \u03c3\u03b5\u03b9\u03c1\u03ac", + "HeaderVideoType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u0392\u03af\u03bd\u03c4\u03b5\u03bf", + "HeaderSeriesStatus": "\u039a\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03a3\u03b5\u03b9\u03c1\u03ac\u03c2", + "Features": "\u03a7\u03b1\u03c1\u03b1\u03ba\u03c4\u03b7\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03ac", + "Trailers": "\u03a4\u03c1\u03ad\u03ca\u03bb\u03b5\u03c1\u03c2", + "Extras": "\u0395\u03c0\u03b9\u03c0\u03bb\u03ad\u03bf\u03bd \u03a5\u03bb\u03b9\u03ba\u03cc", + "ThemeSongs": "\u0398\u03b5\u03bc\u03b1\u03c4\u03b9\u03ba\u03ac \u03c4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1", + "ThemeVideos": "\u0398\u03b5\u03bc\u03b1\u03c4\u03b9\u03ba\u03ac \u03b2\u03af\u03bd\u03c4\u03b5\u03bf", + "HeaderFavoriteMovies": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b5\u03c2 \u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2", + "HeaderFavoriteShows": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b5\u03c2 \u03a3\u03b5\u03b9\u03c1\u03ad\u03c2", + "HeaderFavoriteEpisodes": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1 \u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1", + "HeaderFavoriteVideos": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1 \u0392\u03af\u03bd\u03c4\u03b5\u03bf", + "HeaderFavoriteGames": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1 \u03a0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9\u03b1", + "HeaderFavoriteArtists": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03bf\u03b9 \u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2", + "HeaderFavoriteAlbums": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1 \u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc", + "HeaderFavoriteSongs": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1 \u03a4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1", + "Ascending": "\u0391\u03cd\u03be\u03bf\u03c5\u03c3\u03b1", + "Descending": "\u03a6\u03b8\u03af\u03bd\u03bf\u03c5\u03c3\u03b1", + "ColorPrimaries": "Color primaries", + "ColorSpace": "\u03a7\u03c1\u03c9\u03bc\u03b1\u03c4\u03b9\u03ba\u03cc\u03c2 \u03c7\u03ce\u03c1\u03bf\u03c2", + "ColorTransfer": "\u039c\u03b5\u03c4\u03b1\u03c6\u03bf\u03c1\u03ac \u03c7\u03c1\u03ce\u03bc\u03b1\u03c4\u03bf\u03c2", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "\u0393\u03b9\u03b1 \u03bd\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b9\u03c2 \u03c0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03bc\u03ad\u03bd\u03b5\u03c2 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2, \u03c3\u03c4\u03b1\u03bc\u03b1\u03c4\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03ba\u03b1\u03b9 \u03c3\u03c4\u03b7 \u03c3\u03c5\u03bd\u03ad\u03c7\u03b5\u03b9\u03b1, \u03ba\u03ac\u03bd\u03c4\u03b5 \u03ba\u03bb\u03b9\u03ba \u03c3\u03c4\u03bf \u03b5\u03b9\u03ba\u03bf\u03bd\u03af\u03b4\u03b9\u03bf \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7 \u03c3\u03c4\u03b7\u03bd \u03b5\u03c0\u03ac\u03bd\u03c9 \u03b4\u03b5\u03be\u03b9\u03ac \u03b5\u03bd\u03cc\u03c4\u03b7\u03c4\u03b1 \u03c4\u03b7\u03c2 \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae\u03c2.", + "SubtitleSettingsIntro": "\u0393\u03b9\u03b1 \u03bd\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b7\u03bd \u03c0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03bc\u03ad\u03bd\u03b7 \u03b5\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03c9\u03bd \u03ba\u03b1\u03b9 \u03c4\u03b9\u03c2 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1\u03c2, \u03c3\u03c4\u03b1\u03bc\u03b1\u03c4\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03ba\u03b1\u03b9, \u03c3\u03c4\u03b7 \u03c3\u03c5\u03bd\u03ad\u03c7\u03b5\u03b9\u03b1, \u03ba\u03ac\u03bd\u03c4\u03b5 \u03ba\u03bb\u03b9\u03ba \u03c3\u03c4\u03bf \u03b5\u03b9\u03ba\u03bf\u03bd\u03af\u03b4\u03b9\u03bf \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7 \u03c3\u03c4\u03b7\u03bd \u03b5\u03c0\u03ac\u03bd\u03c9 \u03b4\u03b5\u03be\u03b9\u03ac \u03b5\u03bd\u03cc\u03c4\u03b7\u03c4\u03b1 \u03c4\u03b7\u03c2 \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae\u03c2." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/en-gb.json b/src/bower_components/emby-webcomponents/strings/en-gb.json index 7a1b075395..8718c31d2d 100644 --- a/src/bower_components/emby-webcomponents/strings/en-gb.json +++ b/src/bower_components/emby-webcomponents/strings/en-gb.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active Internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Cancel", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theatre experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Colour primaries", - "ColorSpace": "Colour space", - "ColorTransfer": "Colour transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable colour-coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an e-mail to {0}, and include your e-mail address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an e-mail to {0} from the e-mail address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active Internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active Internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active Internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favourite", - "Favorites": "Favourites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friday", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again. Alternatively, try entering their e-mail address.", - "Guide": "Guide", - "HDPrograms": "HD programmes", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Untick a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External IDs:", - "HeaderFavoriteAlbums": "Favourite Albums", - "HeaderFavoriteArtists": "Favourite Artists", - "HeaderFavoriteCollections": "Favourite Collections", - "HeaderFavoriteEpisodes": "Favourite Episodes", - "HeaderFavoriteGames": "Favourite Games", - "HeaderFavoriteMovies": "Favourite Movies", - "HeaderFavoritePlaylists": "Favourite Playlists", - "HeaderFavoriteShows": "Favourite Shows", - "HeaderFavoriteSongs": "Favourite Songs", - "HeaderFavoriteVideos": "Favourite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wi-Fi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Country:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date/time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Language:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unticked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background colour:", - "LabelTextColor": "Text colour:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background colour:", - "LabelYear": "Year", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0}, inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An e-mail will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the e-mail.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognise that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Monday", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalised groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favourite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorised to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external ID.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programmes", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Saturday", - "Save": "Save", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, DVD order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc.) or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Sunday", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Thursday", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tuesday", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Wednesday", - "WifiRequiredToDownload": "A Wi-Fi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Cancel", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine but we're unable to connect to your Emby Server. Your machine may need a little more time to wake or Emby Server may not be actively running on the machine.", + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Save", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalised groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Language:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognise that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favourite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External IDs:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Country:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Untick a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external ID.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programmes", + "Programs": "Programmes", + "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "LabelKeep:": "Keep:", + "UntilIDelete": "Until I delete", + "UntilSpaceNeeded": "Until space needed", + "Categories": "Categories", + "Sports": "Sports", + "News": "News", + "Movies": "Movies", + "Kids": "Kids", + "EnableColorCodedBackgrounds": "Enable colour-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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active Internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favourites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorised to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favourite Collections", + "HeaderFavoritePlaylists": "Favourite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unticked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active Internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0}, inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again. Alternatively, try entering their e-mail address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active Internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an e-mail to {0} from the e-mail address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an e-mail to {0}, and include your e-mail address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An e-mail will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the e-mail.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background colour:", + "LabelWindowBackgroundColor": "Text background colour:", + "LabelFont": "Font:", + "LabelTextColor": "Text colour:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc.) or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wi-Fi", + "WifiRequiredToDownload": "A Wi-Fi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active Internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theatre experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date\/time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favourite Movies", + "HeaderFavoriteShows": "Favourite Shows", + "HeaderFavoriteEpisodes": "Favourite Episodes", + "HeaderFavoriteVideos": "Favourite Videos", + "HeaderFavoriteGames": "Favourite Games", + "HeaderFavoriteArtists": "Favourite Artists", + "HeaderFavoriteAlbums": "Favourite Albums", + "HeaderFavoriteSongs": "Favourite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Colour primaries", + "ColorSpace": "Colour space", + "ColorTransfer": "Colour transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, DVD order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/en-us.json b/src/bower_components/emby-webcomponents/strings/en-us.json index ec81e54290..cc8a35a108 100644 --- a/src/bower_components/emby-webcomponents/strings/en-us.json +++ b/src/bower_components/emby-webcomponents/strings/en-us.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", + "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", "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Cancel", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Save", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile / Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Language:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Country:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", "AutomaticallySyncNewContent": "Automatically download new content", "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", "Box": "Box", "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Cancel", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", "ColorPrimaries": "Color primaries", "ColorSpace": "Color space", "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friday", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Country:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Language:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Monday", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Saturday", - "Save": "Save", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Sunday", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Thursday", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tuesday", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Wednesday", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/es-ar.json b/src/bower_components/emby-webcomponents/strings/es-ar.json index 0711679784..58f7df84f2 100644 --- a/src/bower_components/emby-webcomponents/strings/es-ar.json +++ b/src/bower_components/emby-webcomponents/strings/es-ar.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Cancel", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friday", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Country:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Language:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Monday", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Ejemplo: Colección de Star Wars", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Saturday", - "Save": "Save", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Sunday", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Thursday", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tuesday", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Wednesday", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Cancel", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Save", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Ejemplo: Colecci\u00f3n de Star Wars", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Language:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Country:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/es-mx.json b/src/bower_components/emby-webcomponents/strings/es-mx.json index 3c35481fc1..70fb1b8865 100644 --- a/src/bower_components/emby-webcomponents/strings/es-mx.json +++ b/src/bower_components/emby-webcomponents/strings/es-mx.json @@ -1,685 +1,689 @@ { - "Absolute": "Absoluto", - "Accept": "Aceptar", - "AccessRestrictedTryAgainLater": "El acceso esta restringido en este momento. Por favor intente de nuevo mas tarde.", - "Actor": "Actor", - "Add": "Agregar", - "AddToCollection": "Agregar a Colección.", - "AddToPlayQueue": "Agregar a la cola de reproduccion", - "AddToPlaylist": "Agregar a lista de reproducción", - "AddedOnValue": "Agregado {0}", - "Advanced": "Avanzado", - "AirDate": "Fecha de emisión", - "Aired": "Transmitido", - "Albums": "Álbumes", - "All": "Todo", - "AllChannels": "Todos los canales", - "AllComplexFormats": "Todos los subtitulos complejos (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Todos los episodios", - "AllLanguages": "Todos los idiomas", - "AllowSeasonalThemes": "Permitir temas de temporada automáticamente", - "AllowSeasonalThemesHelp": "Si esta habilitado, temas de temporada reemplazaran ocasionalmente el tema por defecto.", - "AlwaysPlaySubtitles": "Siempre mostrar subtítulos", - "AlwaysPlaySubtitlesHelp": "Los subtítulos que coincidan con el lenguaje preferido serán cargados independientemente del lenguaje del audio.", - "AnamorphicVideoNotSupported": "Video anamorfico no soportado", - "AndroidUnlockRestoreHelp": "Para restaurar su compra previa, por favor asegúrese de que se encuentra registrado en el dispositivo con la misma cuenta de Google (o Amazon) con que hizo la compra. Asegúrese que la tienda de aplicaciones esta habilitada, no esta restringida por cualquier control parental y que tiene una conexión de internet activa. Esto se tiene que hacer solo una vez para restaurar su compra previa.", - "AnyLanguage": "Cualquier lenguaje", - "Anytime": "En cualquier momento", - "AroundTime": "Alrededor de {0}", - "Art": "Arte", - "Artists": "Artistas", - "AsManyAsPossible": "Tantos como sea posible", - "Ascending": "Ascendente", - "AspectRatio": "Relación de aspecto", - "AttemptingWakeServer": "Intentando despertar el servidor. Por favor espere...", - "AttributeNew": "Nuevo", - "AudioBitDepthNotSupported": "Profundidad de bits de Audio no soportado", - "AudioBitrateNotSupported": "Tasa de bits de audio no soportado", - "AudioChannelsNotSupported": "Canales de audio no soportados", - "AudioCodecNotSupported": "Codec de audio no soportado", - "AudioProfileNotSupported": "Perfil de audio no soportado", - "AudioSampleRateNotSupported": "Muestreo (sample) de audio no soportado", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (basado en la configuración del lenguaje)", - "AutomaticallyConvertNewContent": "Convertir contenidos nuevos automáticamente", - "AutomaticallyConvertNewContentHelp": "Los contenidos nuevos agregados a esta carpeta serán convertidos automáticamente.", - "AutomaticallySyncNewContent": "Descargar automáticamente nuevos contenidos", - "AutomaticallySyncNewContentHelp": "Los contenidos nuevos agregados a esta carpeta serán descargados automáticamente al dispositivo.", - "Backdrop": "Imagen de Fondo", - "Backdrops": "Imágenes de fondo", - "Banner": "Cartél", - "BestFit": "Mejor ajuste", - "BirthLocation": "Lugar de nacimiento", - "Books": "Libros", - "Box": "Caja", - "BoxRear": "Reverso de caja", - "Browse": "Navegar", - "BurnSubtitlesHelp": "Determina si el servidor debería quemar los subtitulos al convertir el video dependiendo en el formato de los subtitulos. Evitar los subtitulos quemados mejorara el rendimiento del servidor. Elija \"Auto\" para quemar los formatos basados en imágenes (por ejemplo VOBSUB, PGS, SUB/IDX, etc.) así como ciertos subtitulos ASS/SSA", - "ButtonCancel": "Cancelar", - "ButtonGotIt": "Hecho", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Reproducir un minuto", - "ButtonRestart": "Reiniciar", - "ButtonRestorePreviousPurchase": "Restaurar Compra", - "ButtonTryAgain": "Intentar de Nuevo", - "ButtonUnlockPrice": "Desbloquear {0}", - "ButtonUnlockWithPurchase": "Desbloquear con una Compra", - "CancelDownload": "Cancelar descarga", - "CancelRecording": "Cancelar grabación", - "CancelSeries": "Cancelar serie", - "Categories": "Categorías", - "ChannelNameOnly": "Canal {0} solamente", - "ChannelNumber": "Numero de canal", - "CinemaModeConfigurationHelp": "El modo cine trae la experiencia del cine directo al la sala de TV con la habilidad de reproducir tráilers e intros personalizados antes de la presentación estelar.", - "CinemaModeFeatureDescription": "El Modo Cine le da una verdadera experiencia de cine con trailers e intros personalizados antes de la función.", - "CloudSyncFeatureDescription": "Sincronice sus medios a la nube para un fácil respaldo, archivo y conversión.", - "Collections": "Colecciones", - "ColorPrimaries": "Colores primarios", - "ColorSpace": "Espacio de color", - "ColorTransfer": "Transferencia de color", - "CommunityRating": "Calificación de la comunidad", - "Composer": "Compositor", - "ConfigureDateAdded": "Configure como la fecha de adición es determinada en el Panel de Control del Servidor Jellyfin bajo la configuración de Bibliotecas", - "ConfirmDeleteImage": "¿Eliminar imagen?", - "ConfirmDeleteItem": "Al eliminar este ítem se eliminará tanto del sistema de archivos como de su biblioteca de medios. ¿Esta seguro de querer continuar?", - "ConfirmDeleteItems": "Al borrar estos items serán eliminados tanto del sistema de archivos como de la biblioteca de medios. ¿Esta seguro que desea continuar?", - "ConfirmDeletion": "Confirmar Eliminación", - "ConfirmEndPlayerSession": "¿Desea cerrar Jellyfin en {0}?", - "ConfirmRemoveDownload": "¿Eliminar descarga?", - "Connect": "Conectar", - "ContainerBitrateExceedsLimit": "La tasa de bits de este medio excede el limite.", - "ContainerNotSupported": "Contenedor no soportado", - "Continue": "Continuar", - "ContinueInSecondsValue": "Continua en {0} segundos.", - "ContinueWatching": "Continuar viendo", - "Continuing": "Continuando", - "Convert": "Convertir", - "ConvertItemLimitHelp": "Opcional. Establecer un límite en el número de ítems que serán convertidos.", - "ConvertUnwatchedVideosOnly": "Convertir ùnicamente videos no vistos", - "ConvertUnwatchedVideosOnlyHelp": "Solo los videos no vistos serán convertidos.", - "ConvertingDots": "Convirtiendo...", - "Countries": "Países", - "CriticRating": "Calificación de la crítica", - "DateAdded": "Fecha de adición", - "DatePlayed": "Fecha de reproducción", - "Days": "Días", - "Default": "Por defecto", - "DefaultErrorMessage": "Ha ocurrido un error al procesar la solicitud. Por favor inténtelo de nuevo mas tarde.", - "DefaultSubtitlesHelp": "Los subtitulos son cargados basados en los indicadores \"por defecto\" y \"forzado\" incluidos en los metadatos. Las preferencias de idioma son consideradas cuando hay múltiples opciones disponibles.", - "Delete": "Eliminar", - "DeleteMedia": "Eliminar medios", - "Depressed": "Depresión", - "Descending": "Descendente", - "Desktop": "Escritorio", - "DirectPlayError": "Error de reproducción directa", - "DirectPlaying": "Reproducción directa", - "DirectStreamHelp1": "El medio es compatible con el dispositivo en cuanto a la resolución y tipo de medio (H.264, AC3, etc.), pero es un es un contenedor de archivo incompatible (.mkv, .avi, .wmv, etc.). El video sera re empaquetado al vuelo antes de transmitirlo al dispositivo.", - "DirectStreamHelp2": "La Transmisión Directa de un archivo usa muy poco poder de procesamiento sin ninguna perdida en la calidad de video.", - "DirectStreaming": "Transmisión Directa", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directores: {0}", - "Disc": "DIsco", - "Disconnect": "Desconectar", - "Dislike": "No me gusta", - "Display": "Pantalla", - "DisplayInMyMedia": "Mostrar en pantalla de inicio", - "DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla de inicio como Recientes o Continua Viendo", - "DisplayMissingEpisodesWithinSeasons": "Desplegar episiodos faltantes en las temporadas", - "DisplayMissingEpisodesWithinSeasonsHelp": "Debe habilitarse también en las bibliotecas de TV en la configuraciòn del Servidor Jellyfin.", - "DisplayModeHelp": "Seleccione el tipo de pantalla en la que se encuentra ejecutando Jellyfin.", - "DoNotRecord": "No grabar", - "Down": "Abajo", - "Download": "Descargar", - "DownloadItemLimitHelp": "Opcional. Establecer un límite en el número de ítems que serán descargados.", - "Downloaded": "Descargado", - "Downloading": "Descargando", - "DownloadingDots": "Descargando...", - "Downloads": "Descargas", - "DownloadsValue": "{0} descargas", - "DropShadow": "Mostrar sombra", - "DvrFeatureDescription": "Programe grabaciones individuales de TV en Vivo, series, y mas con Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR necesita una suscripción activa de Jellyfin Premiere.", - "Edit": "Editar", - "EditImages": "Editar imágenes", - "EditMetadata": "Editar metadatos", - "EditSubtitles": "Editar subtítulos", - "EnableBackdrops": "Habilitar imágenes de fondo", - "EnableBackdropsHelp": "Al habilitarse, las imágenes de fondo serán deplegadas en el fondo de algunas páginas mientras navega en la biblioteca.", - "EnableCinemaMode": "Activar modo cine", - "EnableColorCodedBackgrounds": "Habilitar fondos con código de color", - "EnableDisplayMirroring": "Habilitar duplicación de pantalla", - "EnableExternalVideoPlayers": "Habilitar reproductores externos de video", - "EnableExternalVideoPlayersHelp": "Un menú de reproductor externo se mostrara cuando inicie la reproducción de un video.", - "EnableNextVideoInfoOverlay": "Habilitar ver la información del siguiente video durante la reproducción", - "EnableNextVideoInfoOverlayHelp": "Al finalizar un video, mostrar información sobre el siguiente video a reproducir en la lista de reproducción.", - "EnableThemeSongs": "Habilitar canciones de tema", - "EnableThemeSongsHelp": "Al habilitarse, las canciones de tema serán reproducidas en el fondo mientras navega en la biblioteca.", - "EnableThemeVideos": "Habilitar videos de tema", - "EnableThemeVideosHelp": "Al habilitarse, los videos de tema serán reproducidos en el fondo mientras navega en la biblioteca.", - "Ended": "Finalizado", - "EndsAtValue": "Termina a las {0}", - "Episodes": "Episodios", - "Error": "Error", - "ErrorAddingGuestAccount1": "Hubo un error agregando la cuenta de Jellyfin Connect. ¿Su invitado ya ha creado una cuenta de Jellyfin Connect? Puede registrarse en {0}.", - "ErrorAddingGuestAccount2": "Si continua teniendo problemas, escriba un correo electrónico a {0}, e incluya su dirección de correo electrónico ademas de la de su invitado.", - "ErrorAddingJellyfinConnectAccount1": "Hubo un error agregando la cuenta de Jellyfin Connect. ¿Ya ha creado una cuenta de Jellyfin? Registrese en {0}.", - "ErrorAddingJellyfinConnectAccount2": "Si continua teniendo problemas, por favor envíe un correo electrónico a {0} desde la dirección de correo electrónico usada con la cuenta Jellyfin.", - "ErrorConnectServerUnreachable": "Hubo un error al ejecutar la operación solicitada. Su servidor no puede contactar nuestro servidor de Jellyfin Connect en {0}. Por favor asegúrese de que su servidor tiene una conection a internet activa y que el firewall o software de seguridad permita la comunicación.", - "ErrorDeletingItem": "Hubo un error eliminando el ítem del Servidor Jellyfin. Por favor verifique tenga permisos de escritura en la carpeta de medios e intente de nuevo.", - "ErrorReachingJellyfinConnect": "Hubo un error al tratar de contactar el servidor de Jellyfin Connect. Por favor asegúrese de que tiene una conexión activa de internet e intente de nuevo.", - "ErrorRemovingJellyfinConnectAccount": "Hubo un error retirando la cuenta de Jellyfin Connect. Por favor asegúrese que su conexión a internet esta activa e intente de nuevo.", - "ExtraLarge": "Extra grande", - "Extras": "Extras", - "Favorite": "Favorito", - "Favorites": "Favoritos", - "FeatureRequiresJellyfinPremiere": "Esta característica requiere de una suscripción activa de Jellyfin Premiere.", - "Features": "Características", - "File": "Archivo", - "Fill": "Llenar", - "Filters": "Filtros", - "Folders": "Carpetas", - "FormatValue": "Formato: {0}", - "FreeAppsFeatureDescription": "Disfrute acceso gratuito para elegir aplicaciones Jellyfin para sus dispositivos.", - "Friday": "Viernes", - "GenreValue": "Genero: {0}", - "Genres": "Géneros", - "GenresValue": "Géneros: {0}", - "GroupBySeries": "Agrupar por series", - "GroupVersions": "Agrupar versiones", - "GuestStar": "Estrella invitada", - "GuestUserNotFound": "Usuario no encontrado. Por favor asegúrese de que el nombre es correcto e intente de nuevo, o intente introducir la dirección de correo de su invitado.", - "Guide": "Guía", - "HDPrograms": "Programas en HD", - "HeaderActiveRecordings": "Grabaciones Activas", - "HeaderAddToCollection": "Agregar a Colección", - "HeaderAddToPlaylist": "Agregar a Lista de Reproducción", - "HeaderAddUpdateImage": "Agregar/Actualizar Imagen", - "HeaderAlbumArtists": "Artistas del álbum", - "HeaderAlreadyPaid": "¿Ya ha pagado?", - "HeaderAppearsOn": "Aparece En", - "HeaderAudioBooks": "Audio Libros", - "HeaderAudioSettings": "Configuración de Audio", - "HeaderBecomeProjectSupporter": "Obtener Jellyfin Premier", - "HeaderBenefitsJellyfinPremiere": "Beneficios de Jellyfin Premier", - "HeaderCancelRecording": "Cancelar Grabación", - "HeaderCancelSeries": "Cancelar Serie", - "HeaderCinemaMode": "Modo Cine", - "HeaderCloudSync": "Sincronización en la Nube", - "HeaderConfirmRecordingCancellation": "Confirmar Cancelación de la Grabación", - "HeaderContinueListening": "Continuar Escuchando", - "HeaderContinueWatching": "Continuar Viendo", - "HeaderConvertYourRecordings": "Convertir Sus Grabaciones", - "HeaderCustomizeHomeScreen": "Personalizar la Pantalla de Inicio", - "HeaderDeleteItem": "Eliminar Ítem", - "HeaderDeleteItems": "Borrar items", - "HeaderDisplaySettings": "Configuración de Pantalla", - "HeaderDownloadSettings": "Configuración de Descargas", - "HeaderEditImages": "Editar imágenes", - "HeaderEnabledFields": "Campos Habilitados", - "HeaderEnabledFieldsHelp": "Desmarcar un campo para bloquearlo y prevenir que sus datos cambien.", - "HeaderExternalIds": "IDs Externos:", - "HeaderFavoriteAlbums": "Álbumes Favoritos", - "HeaderFavoriteArtists": "Artistas Favoritos", - "HeaderFavoriteCollections": "Colecciones Favoritas", - "HeaderFavoriteEpisodes": "Episodios Favoritos", - "HeaderFavoriteGames": "Juegos Favoritos", - "HeaderFavoriteMovies": "Películas Favoritas", - "HeaderFavoritePlaylists": "Listas de Reproducción Favoritas", - "HeaderFavoriteShows": "Programas Favoritos", - "HeaderFavoriteSongs": "Canciones Favoritas", - "HeaderFavoriteVideos": "Videos Favoritos", - "HeaderFreeApps": "Aplicaciones Jellyfin Gratuitas", - "HeaderHomeScreen": "Pantalla de Inicio", - "HeaderIdentifyItemHelp": "Introduzca uno o más criterios de búsqueda. Elimine criterios para expandir los resultados.", - "HeaderInvitationSent": "Invitación Enviada", - "HeaderJellyfinAccountAdded": "Cuenta Jellyfin Agregada", - "HeaderJellyfinAccountRemoved": "Cuenta Jellyfin Eliminada", - "HeaderKeepRecording": "Conservar Grabaciones", - "HeaderKeepSeries": "Conservar Serie", - "HeaderLatestChannelItems": "Ítems Recientes de Canales", - "HeaderLatestChannelMedia": "Ítems Recientes de Canales", - "HeaderLatestFrom": "Más recientes desde {0}", - "HeaderLatestMedia": "Agregadas Recientemente", - "HeaderLatestRecordings": "Grabaciones Recientes", - "HeaderLearnMore": "Aprenda más", - "HeaderLibraryFolders": "Carpetas de Biblioteca", - "HeaderLibraryOrder": "Orden de Bibliotecas", - "HeaderMetadataSettings": "Configuración de metadatos", - "HeaderMusicQuality": "Calidad de Musica", - "HeaderMyDevice": "Mi Dispositivo", - "HeaderMyDownloads": "Mis Descargas", - "HeaderMyMedia": "Mis Medios", - "HeaderMyMediaSmall": "Mis medios (pequeño)", - "HeaderNewRecording": "Nueva Grabación", - "HeaderNextEpisodePlayingInValue": "El Siguiente Episodio se Reproducirá en {0}", - "HeaderNextUp": "A Continuación", - "HeaderNextVideoPlayingInValue": "El Siguiente Video se Reproducirá en {0}", - "HeaderOfflineDownloads": "Medios sin conexion", - "HeaderOfflineDownloadsDescription": "Descargue sus medios en su dispositivo para fácil uso mientras esta desconectado.", - "HeaderOnNow": "Transmitiéndo Ahora", - "HeaderPhotoAlbums": "Álbumes de Fotos", - "HeaderPlayMyMedia": "Reproducir mis Medios", - "HeaderPlayOn": "Reproducir En", - "HeaderPlaybackError": "Error de Reproducción", - "HeaderRecordingOptions": "Opciones de Grabación", - "HeaderRemoteControl": "Control Remoto", - "HeaderRestartingJellyfinServer": "Reiniciando el Servidor Jellyfin", - "HeaderSaySomethingLike": "Decir Algo Como...", - "HeaderSecondsValue": "{0} Segundos", - "HeaderSelectDate": "Seleccionar fecha", - "HeaderSeriesOptions": "Opciones de Serie", - "HeaderSeriesStatus": "Estado de la Serie", - "HeaderSpecialEpisodeInfo": "Información del Episodio Especial", - "HeaderStartNow": "Iniciar Ahora", - "HeaderStopRecording": "Detener Grabación", - "HeaderSubtitleAppearance": "Apariencia de Subtitulos", - "HeaderSubtitleSettings": "Configuración de Subtitulos", - "HeaderSyncRequiresSub": "Descargar requiere de una suscripción activa de Jellyfin Premiere", - "HeaderTermsOfPurchase": "Términos de Compra", - "HeaderTryPlayback": "Intente Reproducir", - "HeaderUnlockFeature": "Desbloquear Característica", - "HeaderUploadImage": "Subir Imagen", - "HeaderVideoQuality": "Calidad de Video", - "HeaderVideoType": "Tipo de Video", - "HeaderWaitingForWifi": "Esperando Wifi", - "HeaderWakeServer": "Despertar Servidor", - "HeaderYouSaid": "Ha Dicho...", - "Help": "Ayuda", - "Hide": "Ocultar", - "HideWatchedContentFromLatestMedia": "Ocultar contenido ya visto de Agregadas Recientemente", - "Home": "Inicio", - "Horizontal": "Horizontal", - "HowDidYouPay": "¿Cual sera su forma de pago?", - "IHaveJellyfinPremiere": "Ya cuento con Jellyfin Premiere", - "IPurchasedThisApp": "Ya he comprado esta app", - "Identify": "Identificar", - "Images": "Imágenes", - "ImdbRating": "Calificación de IMDb", - "InstallingPackage": "Instalando {0}", - "InstantMix": "Mix instantáneo", - "InterlacedVideoNotSupported": "Video entrelazado no soportado", - "ItemCount": "{0} ítems", - "Items": "Ítems", - "KeepDownload": "Seguir descargando", - "KeepOnDevice": "Conservar en el dispositivo", - "Kids": "Niños", - "Label3DFormat": "Formato 3D:", - "LabelAirDays": "Se emite los días:", - "LabelAirTime": "Duración:", - "LabelAirsAfterSeason": "Transmisión después de la temporada:", - "LabelAirsBeforeEpisode": "Transmisión antes del episodio:", - "LabelAirsBeforeSeason": "Transmisión antes de la temporada:", - "LabelAlbum": "Álbum", - "LabelAlbumArtists": "Artistas del álbum:", - "LabelArtists": "Artistas:", - "LabelArtistsHelp": "Separar múltiples empleando:", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Idioma preferido de audio:", - "LabelBirthDate": "Fecha de Nacimiento:", - "LabelBirthYear": "Año de nacimiento:", - "LabelBitrateMbps": "Tasa de bits (Mbps):", - "LabelBurnSubtitles": "Subtitulos quemados:", - "LabelChannels": "Canales:", - "LabelCollection": "Colección:", - "LabelCommunityRating": "Calificación de la comunidad:", - "LabelContentType": "Tipo de Contenido:", - "LabelConvertTo": "Convertir a:", - "LabelCountry": "País:", - "LabelCriticRating": "Calificación de la crítica:", - "LabelCustomRating": "Calificación personalizada:", - "LabelDashboardTheme": "Tema del panel de control del Servidor:", - "LabelDateAdded": "Fecha de adición:", - "LabelDateTimeLocale": "Configuración regional de Fecha y Hora:", - "LabelDeathDate": "Fecha de defunción:", - "LabelDefaultScreen": "Pantalla por defecto:", - "LabelDiscNumber": "Número de disco:", - "LabelDisplayLanguage": "Lenguaje de Despliege:", - "LabelDisplayLanguageHelp": "La traducción de Jellyfin es un proyecto en curso.", - "LabelDisplayMode": "Modo de Pantalla:", - "LabelDisplayOrder": "Orden para mostrar:", - "LabelDropImageHere": "Arrastre la imagen aquí, o de clic para navegar.", - "LabelDropShadow": "Mostrar sombra:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "Dirección de correo:", - "LabelEndDate": "Fecha de Fin:", - "LabelEpisodeNumber": "Episodio numero:", - "LabelFont": "Fuente:", - "LabelHomeNetworkQuality": "Calidad en Red Local:", - "LabelHomeScreenSectionValue": "Pagina de inicio sección {0}:", - "LabelImageType": "Tipo de imagen:", - "LabelInternetQuality": "Calidad en internet:", - "LabelItemLimit": "Límite de Ítems:", - "LabelKeep:": "Mantener:", - "LabelKeepUpTo": "Mantener hasta:", - "LabelLanguage": "Idioma:", - "LabelLockItemToPreventChanges": "Bloquear este ítem para evitar cambios futuros", - "LabelMaxChromecastBitrate": "Tasa maxima de bits para El Chromecast:", - "LabelMetadataDownloadLanguage": "Lenguaje preferido para descargas:", - "LabelName": "Nombre:", - "LabelNumber": "Número:", - "LabelOriginalAspectRatio": "Relación de aspecto original:", - "LabelOriginalTitle": "Titulo original:", - "LabelOverview": "Sinopsis:", - "LabelParentNumber": "Número antecesor:", - "LabelParentalRating": "Clasificación parental:", - "LabelPath": "Ruta:", - "LabelPersonRole": "Rol:", - "LabelPersonRoleHelp": "Ejemplo: Conductor de camión de helados", - "LabelPlaceOfBirth": "Lugar de nacimiento:", - "LabelPlayDefaultAudioTrack": "Reproducir la pista de audio por defecto independientemente del lenguaje", - "LabelPlaylist": "Lista de Reproducción:", - "LabelPreferredSubtitleLanguage": "Idioma preferido para subtitulos:", - "LabelProfile": "Perfíl:", - "LabelQuality": "Calidad:", - "LabelReasonForTranscoding": "Motivo para transcodificar:", - "LabelRecord": "Grabar:", - "LabelRefreshMode": "Modo de actualización:", - "LabelReleaseDate": "Fecha de estreno:", - "LabelRuntimeMinutes": "Duración (minutos):", - "LabelScreensaver": "Protector de Pantalla:", - "LabelSeasonNumber": "Temporada numero:", - "LabelSelectFolderGroups": "Agrupar automáticamente el contenido de las siguientes carpetas en vistas tales como Películas, Música y TV:", - "LabelSelectFolderGroupsHelp": "Las carpetas sin marcar serán mostradas individualmente en su propia vista.", - "LabelShortOverview": "Sinopsis corta:", - "LabelSkin": "Piel:", - "LabelSkipBackLength": "Longitud de salto hacia atrás:", - "LabelSkipForwardLength": "Longitud de salto hacia adelante:", - "LabelSortBy": "Ordenar por:", - "LabelSortOrder": "Modo de ordenar:", - "LabelSortTitle": "Titulo para ordenar:", - "LabelSoundEffects": "Efectos de Sonido:", - "LabelSource": "Fuente:", - "LabelStartWhenPossible": "Iniciar cuando sea posible:", - "LabelStatus": "Estado:", - "LabelStopWhenPossible": "Detener cuando sea posible:", - "LabelSubtitlePlaybackMode": "Modo de subtítulo:", - "LabelSubtitles": "Subtítulos:", - "LabelSyncJobName": "Nombre del trabajo de sincronización:", - "LabelSyncNoTargetsHelp": "Parece que actualmente no cuentas con ninguna app que soporte descargas sin conexión.", - "LabelSyncTo": "Sincronizar con:", - "LabelTVHomeScreen": "Modo de pantalla de TV:", - "LabelTagline": "Eslogan", - "LabelTextBackgroundColor": "Color de fondo para el texto:", - "LabelTextColor": "Color de texto:", - "LabelTextSize": "Tamaño de texto:", - "LabelTheme": "Tema:", - "LabelTitle": "Titulo:", - "LabelTrackNumber": "Número de Pista:", - "LabelType": "Tipo:", - "LabelVersion": "Versión:", - "LabelVideo": "Video:", - "LabelWebsite": "Sitio web:", - "LabelWindowBackgroundColor": "Color de fondo para el texto:", - "LabelYear": "Año:", - "Large": "Grande", - "LatestFromLibrary": "Más recientes {0}", - "LearnHowYouCanContribute": "Aprenda como puede contribuír.", - "LearnMore": "Aprenda más", - "Like": "Me gusta", - "LinksValue": "Enlaces: {0}", - "List": "Lista", - "Live": "En Vivo", - "LiveBroadcasts": "Transmisiones en vivo", - "LiveTV": "TV en Vivo", - "LiveTvFeatureDescription": "Transmita TV en vivo a una aplicación Jellyfin, instalando un dispositivo sintonizador de TV compatible con su Servidor Jellyfin", - "LiveTvRequiresUnlock": "TV en vivo requiere una subscripción activa de Jellyfin Premiere", - "Logo": "Logotipo", - "ManageRecording": "Administrar grabaciones", - "MarkPlayed": "Marcar como Reproducido", - "MarkUnplayed": "Marcar como No Reproducido", - "MarkWatched": "Marcar como Visto", - "MediaIsBeingConverted": "Los medios están siendo convertidos a un formato compatible con el dispositivo que esta reproduciendo el medio.", - "Medium": "Mediano", - "Menu": "Menú", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Se requiere de una suscripción de Jellyfin Premier para crear grabaciones automatizadas de series.", - "MessageAreYouSureDeleteSubtitles": "¿Está seguro de querer eliminar este archivo de subtitulos?", - "MessageConfirmRecordingCancellation": "¿cancelar esta grabación?", - "MessageDownloadQueued": "Descargar cola.", - "MessageFileReadError": "Hubo un error al leer el archivo. Por favor intente de nuevo.", - "MessageIfYouBlockedVoice": "Si ha negado el acceso a la voz a la aplicación necesitara reconfigurar antes de intentarlo de nuevo.", - "MessageInvitationSentToNewUser": "Un correo electrónico se ha enviado a {0} invitándolos a registrarse en Jellyfin.", - "MessageInvitationSentToUser": "Se ha enviado un correo electrónico a {0}, invitándolo a aceptar tu invitación para compartir.", - "MessageItemSaved": "Ítem guardado.", - "MessageItemsAdded": "Ítems agregados.", - "MessageJellyfinAccontRemoved": "La cuenta Jellyfin ha sido eliminada de este usuario.", - "MessageJellyfinAccountAdded": "La cuenta Jellyfin ha sido agregada a este usuario.", - "MessageLeaveEmptyToInherit": "Dejar vacío para heredar la configuración del ítem padre, o el valor global por omisión.", - "MessageNoDownloadsFound": "No hay elementos sin conexión. Descargue sus medios para usarlos sin conexion haciendo clic en Descargar través de la app.", - "MessageNoServersAvailableToConnect": "No hay servidores disponibles para conectarse. Si se le ha invitado a compartir un servidor, asegúrese de aceptarlo aquí abajo o haciendo clic en la liga del correo electrónico.", - "MessageNoSyncJobsFound": "No se han encontrado descargas. Cree descargas empleando los botones de Sincronizar en la app.", - "MessagePendingJellyfinAccountAdded": "La cuenta Jellyfin ha sido agregada a este usuario. Se enviara un correo electrónico al propietario de la cuenta. La invitación necesitara ser confirmada dando clic al enlace dentro del correo electrónico.", - "MessagePlayAccessRestricted": "La reproducción de este contenido se encuentra restringida actualmente. Por favor contacte a su administrador del Servidor Jellyfin para mas información.", - "MessageToValidateSupporter": "Si tiene una subscripción de Jellyfin Premiere activa, asegúrese de que ha configurado Jellyfin Premiere en el Panel de Control del Servidor Jellyfin, al cual puede acceder dando click en Jellyfin Premiere dentro del menú principal.", - "MessageUnlockAppWithPurchaseOrSupporter": "Desbloquee esta característica con una pequeña compra única, o con una suscripción activa de Jellyfin Premier.", - "MessageUnlockAppWithSupporter": "Desbloquee esta característica con una suscripción activa de Jellyfin Premier.", - "MessageWeDidntRecognizeCommand": "Lo sentimos, no reconocimos ese comando.", - "MinutesAfter": "minutos despues", - "MinutesBefore": "Minutos antes", - "Mobile": "Móvil / Tableta", - "Monday": "Lunes", - "More": "Mas", - "MoveLeft": "Mover a la izquierda", - "MoveRight": "Mover a la derecha", - "Movies": "Películas", - "MySubtitles": "Mis Subtitulos", - "Name": "Nombre", - "NewCollection": "Nueva Colección", - "NewCollectionHelp": "Las colecciones le permiten disfrutar de agrupaciones personalizadas de películas y otros contenidos de la biblioteca.", - "NewCollectionNameExample": "Ejemplo: Colección Guerra de las Galaxias", - "NewEpisodes": "Episodios nuevos", - "NewEpisodesOnly": "Solo episodios nuevos", - "News": "Noticias", - "Next": "Siguiente", - "No": "No", - "NoItemsFound": "No se encontraron ítems.", - "NoSubtitleSearchResultsFound": "No se encontraron resultados.", - "NoSubtitles": "Sin Subtitulos", - "NoSubtitlesHelp": "Los subtítulos no serán cargados por defecto. Pero pueden ser activados manualmente durante la reproducción.", - "None": "Ninguno", - "Normal": "Normal", - "Off": "Apagar", - "OneChannel": "Un canal", - "OnlyForcedSubtitles": "Únicamente subtítulos forzados", - "OnlyForcedSubtitlesHelp": "Se cargarán únicamente subtítulos marcados como forzados.", - "OnlyImageFormats": "Solo formato de imagen (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Abrir", - "OptionNew": "Nuevo...", - "Original": "Original", - "OriginalAirDateValue": "Fecha de emisión original: {0}", - "Overview": "Sinopsis", - "PackageInstallCancelled": "{0} instalación cancelada.", - "PackageInstallCompleted": "{0} instalación completada.", - "PackageInstallFailed": "{0} instalación fallida.", - "ParentalRating": "Clasificación Parental", - "People": "Personas", - "PerfectMatch": "Coincidencia exacta", - "Photos": "Fotos", - "PlaceFavoriteChannelsAtBeginning": "Colocar canales favoritos al inicio", - "Play": "Reproducir", - "PlayAllFromHere": "Reproducir todos desde aquí", - "PlayCount": "Cantidad de reproducciones", - "PlayFromBeginning": "Reproducir desde el inicio", - "PlayNext": "Reproducir siguiente", - "PlayNextEpisodeAutomatically": "Reproducir el siguiente episodio automáticamente", - "PlaybackErrorNoCompatibleStream": "No hay streams compatibles en este en este momento. Por favor intente de nuevo mas tarde o contacte a su administrador de sistema para mas detalles.", - "PlaybackErrorNotAllowed": "Actualmente no esta autorizado para reproducir este contenido. Por favor contacte a su administrador de sistema para mas información.", - "PlaybackErrorPlaceHolder": "Por favor introduzca el disco para poder reproducir este video.", - "PlaybackSettings": "Configuraciones de Reproducción", - "PlaybackSettingsIntro": "Para configurar las opciones de reproducción predeterminadas, detenga la reproducción de video. entonces de clic en su icono de usuario en la esquina superior derecha de la aplicación.", - "Played": "Reproducido", - "Playlists": "Listas de reproducción", - "PleaseEnterNameOrId": "Por favor introduzca un nombre o id externo.", - "PleaseRestartServerName": "Por favor reinicie el Servidor Jellyfin - {0}.", - "PleaseSelectDeviceToSyncTo": "Por favor seleccione un dispositivo con al que desee descargar.", - "PleaseSelectTwoItems": "Por favor selecciona al menos dos ítems.", - "Premiere": "Premier", - "Premieres": "Estrenos", - "Previous": "Anterior", - "Primary": "Principal", - "PrivacyPolicy": "Política de privacidad", - "Producer": "Productor", - "ProductionLocations": "Lugares de produccion", - "Programs": "Programas", - "PromoConvertRecordingsToStreamingFormat": "Convertir automáticamente grabaciones a un formato amigable para transmitir con Jellyfin Premiere. Las grabaciones serán convertidos en tiempo real a MP4 o MKV, basado en las configuraciones del Servidor Jellyfin.", - "Quality": "Calidad", - "QueueAllFromHere": "Encolar todos desde aquí", - "Raised": "Elevacion", - "RecentlyWatched": "Visto recientemente", - "Record": "Grabar", - "RecordSeries": "Grabar Series", - "RecordingCancelled": "Grabación cancelada.", - "RecordingScheduled": "Grabación programada.", - "Recordings": "Grabaciones", - "RefFramesNotSupported": "Cantidad de cuadros de referencia del Video no soportado", - "Refresh": "Actualizar", - "RefreshDialogHelp": "Los metadatos son actualizados basándose en las configuraciones y servicios de internet que que estén activados en el panel de control de su Servidor de Jellyfin.", - "RefreshMetadata": "Actualizar metadatos", - "RefreshQueued": "Actualización programada", - "Reject": "Rechazar", - "ReleaseDate": "Fecha de estreno", - "RemoveDownload": "Eliminar descarga", - "RemoveFromCollection": "Remover de la colección", - "RemoveFromPlaylist": "Eliminar de la lista de reproducción", - "RemovingFromDevice": "Eliminando del dispositivo", - "Repeat": "Repetir", - "RepeatAll": "Repetir todas", - "RepeatEpisodes": "Repetir episodios", - "RepeatMode": "Modo de repeticion", - "RepeatOne": "Repetir uno", - "ReplaceAllMetadata": "Remplazar todos los metadatos", - "ReplaceExistingImages": "Reemplazar imágenes existentes", - "RestartPleaseWaitMessage": "Por favor espere mientras el Servidor Jellyfin cierra y reinicia. Este puede tomar un minuto o dos.", - "ResumeAt": "Reanudar desde {0}", - "Retry": "Volver a intentar", - "RunAtStartup": "Ejecutar al iniciar", - "Runtime": "Duración", - "Saturday": "Sábado", - "Save": "Guardar", - "ScanForNewAndUpdatedFiles": "Buscar archivos nuevos y actualizados", - "Schedule": "Programacion", - "Screenshot": "Captura de pantalla", - "Screenshots": "Capturas de pantalla", - "Search": "Buscar", - "SearchForCollectionInternetMetadata": "Buscar en internet ilustraciones y metadatos", - "SearchForMissingMetadata": "Buscar metadatos faltantes", - "SearchForSubtitles": "Buscar Subtitulos", - "SearchResults": "Resultados de la búsqueda", - "SecondaryAudioNotSupported": "Cambio de pista de audio no soportado", - "SeriesCancelled": "Serie cancelada.", - "SeriesDisplayOrderHelp": "Ordenar los episodios por fecha transmisión, orden del dvd o por su numeración absoluta.", - "SeriesRecordingScheduled": "Grabación de series programadas.", - "SeriesSettings": "Configuración de la Serie", - "SeriesYearToPresent": "{0} - Actualidad", - "ServerNameIsRestarting": "El Servidor Jellyfin - {0} se esta reiniciando.", - "ServerNameIsShuttingDown": "El Servidor Jellyfin - {0} se esta apagando.", - "ServerUpdateNeeded": "Este Servidor Jellyfin necesita ser actualizado. Para descargar la ultima versión, por favor visite {0}", - "Settings": "Configuración", - "SettingsSaved": "Configuración guardada.", - "Share": "Compartir", - "ShowIndicatorsFor": "Mostrar indicadores para:", - "ShowTitle": "Mostrar titulo", - "ShowYear": "Mostrar año", - "Shows": "Programas", - "Shuffle": "Aleatorio", - "SkipEpisodesAlreadyInMyLibrary": "No grabar episodios que ya se encuentran en mi biblioteca", - "SkipEpisodesAlreadyInMyLibraryHelp": "Los episodios serán comparados usando el numero de temporada y de episodio, cuando estén disponibles.", - "Small": "Pequeño", - "SmallCaps": "Mayúsculas pequeñas", - "Smaller": "Más pequeño", - "Smart": "Inteligente", - "SmartSubtitlesHelp": "Los subtítulos que coincidan con el lenguaje preferido serán cargados cuando el audio se encuentre en un lenguaje extranjero.", - "Songs": "Canciones", - "Sort": "Ordenar", - "SortByValue": "Ordenar por {0}", - "SortChannelsBy": "Ordenar canales por:", - "SortName": "Nombre para ordenar", - "Sports": "Deportes", - "StatsForNerds": "Estadísticas para los nerds", - "StopRecording": "Detener grabación", - "Studios": "Estudios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Estos ajustes también aplican a cualquier reproducción de Chromecast iniciada por este dispositivo.", - "SubtitleAppearanceSettingsDisclaimer": "Estas configuraciones no se aplicaran a subtitulos gráficos (PGS, DVD, etc.) o a subtitulos que tienen sus propias fuentes embebidas (ASS/SSA).", - "SubtitleCodecNotSupported": "Formato de subtitulo no soportado", - "SubtitleSettings": "Configuraciones de Subtitulos", - "SubtitleSettingsIntro": "Para configurar la apariencia predeterminada de los subtitulos e idioma, detenga la reproducción de video, entonces de clic en su icono de usuario en la parte superior derecha de la aplicación.", - "Subtitles": "Subtítulos", - "Suggestions": "Sugerencias", - "Sunday": "Domingo", - "Sync": "Sincronizar", - "SyncJobItemStatusCancelled": "Cancelado", - "SyncJobItemStatusConverting": "Convirtiendo", - "SyncJobItemStatusFailed": "Falló", - "SyncJobItemStatusQueued": "En cola", - "SyncJobItemStatusReadyToTransfer": "Listo para Transferir", - "SyncJobItemStatusRemovedFromDevice": "Eliminado del dispositivo", - "SyncJobItemStatusSynced": "Descargado", - "SyncJobItemStatusSyncedMarkForRemoval": "Eliminando del dispositivo", - "SyncJobItemStatusTransferring": "Transfiriendo", - "SyncUnwatchedVideosOnly": "Descargar únicamente videos no vistos", - "SyncUnwatchedVideosOnlyHelp": "Solamente los videos aún no vistos serán descargados, se eliminarán los videos del dispositivo conforme éstos sean vistos.", - "SyncingDots": "Sincronizando...", - "TV": "TV", - "Tags": "Etiquetas", - "TagsValue": "Etiquetas: {0}", - "TermsOfUse": "Términos de uso", - "ThankYouForTryingEnjoyOneMinute": "Por favor disfrute de un minuto de reproducción. Gracias por probar Jellyfin.", - "ThemeSongs": "Canciones de Tema", - "ThemeVideos": "Videos de Tema", - "TheseSettingsAffectSubtitlesOnThisDevice": "Estas configuraciones solo afectan subtitulo de este dispositivo", - "Thumb": "Miniatura", - "Thursday": "Jueves", - "TrackCount": "{0} Pistas", - "Trailer": "Trailer", - "Trailers": "Tráilers", - "Transcoding": "Transcodificando", - "TryMultiSelect": "Intente Multi-Selección", - "TryMultiSelectMessage": "Para editar múltiples medios, solo de clic sostenido sobre cualquier póster y elija los items que desea administrar. ¡inténtelo!", - "Tuesday": "Martes", - "Uniform": "Uniforme", - "UnlockGuide": "Desbloquear Guía", - "Unplayed": "No reproducido", - "Unrated": "Sin clasificar", - "UntilIDelete": "Hasta que yo lo borre", - "UntilSpaceNeeded": "Hasta que se necesite espacio", - "Up": "Arriba", - "Upload": "Subir", - "ValueAlbumCount": "{0} álbumes", - "ValueDiscNumber": "Disco {0}", - "ValueEpisodeCount": "{0} episodios", - "ValueGameCount": "{0} juegos", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} películas", - "ValueMusicVideoCount": "{0} videos musicales", - "ValueOneAlbum": "1 álbum", - "ValueOneEpisode": "1 episodio", - "ValueOneGame": "1 juego", - "ValueOneItem": "1 Ítem", - "ValueOneMovie": "1 película", - "ValueOneMusicVideo": "1 video musical", - "ValueOneSeries": "1 serie", - "ValueOneSong": "1 canción", - "ValueSeconds": "{0} segundos", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} canciones", - "ValueSpecialEpisodeName": "Especial - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Profundidad de bits de Video no soportado", - "VideoCodecNotSupported": "Codec de video no soportado", - "VideoFramerateNotSupported": "Tasa de Cuadros por Segundo del video no soportado", - "VideoLevelNotSupported": "Nivel de video no soportado", - "VideoProfileNotSupported": "Perfil de video no soportado", - "VideoRange": "Rango de video", - "VideoResolutionNotSupported": "Resolución de video no soportada", - "ViewAlbum": "Ver album", - "ViewArtist": "Ver artista", - "VoiceInput": "Entrada de Voz", - "WakeServer": "Despertar servidor", - "WakeServerError": "Se enviaron los paquetes Wake On LAN (Despertar por red) a su computadora servidor, pero no ha sido posible contactar a su Servidor Jellyfin. Su computadora quizás necesite un poco mas de tiempo para despertar, o tal vez la aplicación de Servidor Jellyfin no se esta ejecutando en la computadora.", - "WakeServerSuccess": "¡Éxito!", - "Watched": "Visto", - "Wednesday": "Miércoles", - "WifiRequiredToDownload": "Se necesita de una conexión Wifi para continuar descargando.", - "Writer": "Escritor", - "Yes": "Sí" -} + "PlaybackSettings": "Configuraciones de Reproducci\u00f3n", + "SubtitleSettings": "Configuraciones de Subtitulos", + "MessageUnlockAppWithPurchaseOrSupporter": "Desbloquee esta caracter\u00edstica con una peque\u00f1a compra \u00fanica, o con una suscripci\u00f3n activa de Emby Premier.", + "MessageUnlockAppWithSupporter": "Desbloquee esta caracter\u00edstica con una suscripci\u00f3n activa de Emby Premier.", + "MessageToValidateSupporter": "Si tiene una subscripci\u00f3n de Emby Premiere activa, aseg\u00farese de que ha configurado Emby Premiere en el Panel de Control del Servidor Emby, al cual puede acceder dando click en Emby Premiere dentro del men\u00fa principal.", + "ValueSpecialEpisodeName": "Especial - {0}", + "Share": "Compartir", + "Add": "Agregar", + "ServerUpdateNeeded": "Este Servidor Emby necesita ser actualizado. Para descargar la ultima versi\u00f3n, por favor visite {0}", + "LiveTvRequiresUnlock": "TV en vivo requiere una subscripci\u00f3n activa de Emby Premiere", + "AttributeNew": "Nuevo", + "Premiere": "Premier", + "Live": "En Vivo", + "Repeat": "Repetir", + "TrackCount": "{0} Pistas", + "ItemCount": "{0} \u00edtems", + "OriginalAirDateValue": "Fecha de emisi\u00f3n original: {0}", + "EndsAtValue": "Termina a las {0}", + "HeaderSelectDate": "Seleccionar fecha", + "Watched": "Visto", + "AirDate": "Fecha de emisi\u00f3n", + "Played": "Reproducido", + "ButtonOk": "Ok", + "ButtonCancel": "Cancelar", + "AccessRestrictedTryAgainLater": "El acceso esta restringido en este momento. Por favor intente de nuevo mas tarde.", + "ButtonGotIt": "Hecho", + "ButtonRestart": "Reiniciar", + "RecordingCancelled": "Grabaci\u00f3n cancelada.", + "SeriesCancelled": "Serie cancelada.", + "RecordingScheduled": "Grabaci\u00f3n programada.", + "SeriesRecordingScheduled": "Grabaci\u00f3n de series programadas.", + "HeaderNewRecording": "Nueva Grabaci\u00f3n", + "WakeServer": "Despertar servidor", + "HeaderWakeServer": "Despertar Servidor", + "AttemptingWakeServer": "Intentando despertar el servidor. Por favor espere...", + "WakeServerSuccess": "\u00a1\u00c9xito!", + "HeaderCustomizeHomeScreen": "Personalizar la Pantalla de Inicio", + "WakeServerError": "Se enviaron los paquetes Wake On LAN (Despertar por red) a su computadora servidor, pero no ha sido posible contactar a su Servidor Emby. Su computadora quiz\u00e1s necesite un poco mas de tiempo para despertar, o tal vez la aplicaci\u00f3n de Servidor Emby no se esta ejecutando en la computadora.", + "Sunday": "Domingo", + "Monday": "Lunes", + "Tuesday": "Martes", + "Wednesday": "Mi\u00e9rcoles", + "Thursday": "Jueves", + "Friday": "Viernes", + "Saturday": "S\u00e1bado", + "Days": "D\u00edas", + "SortByValue": "Ordenar por {0}", + "LabelSortBy": "Ordenar por:", + "LabelSortOrder": "Modo de ordenar:", + "HeaderPhotoAlbums": "\u00c1lbumes de Fotos", + "Photos": "Fotos", + "HeaderAppearsOn": "Aparece En", + "List": "Lista", + "RecordSeries": "Grabar Series", + "HeaderCinemaMode": "Modo Cine", + "HeaderCloudSync": "Sincronizaci\u00f3n en la Nube", + "Downloads": "Descargas", + "HeaderMyDownloads": "Mis Descargas", + "HeaderOfflineDownloads": "Medios sin conexion", + "HeaderOfflineDownloadsDescription": "Descargue sus medios en su dispositivo para f\u00e1cil uso mientras esta desconectado.", + "CloudSyncFeatureDescription": "Sincronice sus medios a la nube para un f\u00e1cil respaldo, archivo y conversi\u00f3n.", + "LiveTvFeatureDescription": "Transmita TV en vivo a una aplicaci\u00f3n Emby, instalando un dispositivo sintonizador de TV compatible con su Servidor Emby", + "DvrFeatureDescription": "Programe grabaciones individuales de TV en Vivo, series, y mas con Emby DVR.", + "CinemaModeFeatureDescription": "El Modo Cine le da una verdadera experiencia de cine con trailers e intros personalizados antes de la funci\u00f3n.", + "HeaderFreeApps": "Aplicaciones Emby Gratuitas", + "FreeAppsFeatureDescription": "Disfrute acceso gratuito para elegir aplicaciones Emby para sus dispositivos.", + "HeaderBecomeProjectSupporter": "Obtener Emby Premier", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Se requiere de una suscripci\u00f3n de Emby Premier para crear grabaciones automatizadas de series.", + "LabelEmailAddress": "Direcci\u00f3n de correo:", + "PromoConvertRecordingsToStreamingFormat": "Convertir autom\u00e1ticamente grabaciones a un formato amigable para transmitir con Emby Premiere. Las grabaciones ser\u00e1n convertidos en tiempo real a MP4 o MKV, basado en las configuraciones del Servidor Emby.", + "FeatureRequiresEmbyPremiere": "Esta caracter\u00edstica requiere de una suscripci\u00f3n activa de Emby Premiere.", + "HeaderConvertYourRecordings": "Convertir Sus Grabaciones", + "Record": "Grabar", + "Save": "Guardar", + "Edit": "Editar", + "Download": "Descargar", + "Downloaded": "Descargado", + "Downloading": "Descargando", + "Advanced": "Avanzado", + "Delete": "Eliminar", + "HeaderDeleteItem": "Eliminar \u00cdtem", + "ConfirmDeleteItem": "Al eliminar este \u00edtem se eliminar\u00e1 tanto del sistema de archivos como de su biblioteca de medios. \u00bfEsta seguro de querer continuar?", + "Refresh": "Actualizar", + "RefreshQueued": "Actualizaci\u00f3n programada", + "AddToCollection": "Agregar a Colecci\u00f3n.", + "HeaderAddToCollection": "Agregar a Colecci\u00f3n", + "NewCollection": "Nueva Colecci\u00f3n", + "LabelCollection": "Colecci\u00f3n:", + "Help": "Ayuda", + "LabelDisplayMode": "Modo de Pantalla:", + "Desktop": "Escritorio", + "Mobile": "M\u00f3vil \/ Tableta", + "TV": "TV", + "DisplayModeHelp": "Seleccione el tipo de pantalla en la que se encuentra ejecutando Emby.", + "LabelDisplayLanguage": "Lenguaje de Despliege:", + "LabelDisplayLanguageHelp": "La traducci\u00f3n de Emby es un proyecto en curso.", + "LearnHowYouCanContribute": "Aprenda como puede contribu\u00edr.", + "NewCollectionHelp": "Las colecciones le permiten disfrutar de agrupaciones personalizadas de pel\u00edculas y otros contenidos de la biblioteca.", + "SearchForCollectionInternetMetadata": "Buscar en internet ilustraciones y metadatos", + "DisplayMissingEpisodesWithinSeasons": "Desplegar episiodos faltantes en las temporadas", + "DisplayMissingEpisodesWithinSeasonsHelp": "Debe habilitarse tambi\u00e9n en las bibliotecas de TV en la configuraci\u00f2n del Servidor Emby.", + "EnableThemeSongs": "Habilitar canciones de tema", + "EnableBackdrops": "Habilitar im\u00e1genes de fondo", + "EnableThemeSongsHelp": "Al habilitarse, las canciones de tema ser\u00e1n reproducidas en el fondo mientras navega en la biblioteca.", + "EnableBackdropsHelp": "Al habilitarse, las im\u00e1genes de fondo ser\u00e1n deplegadas en el fondo de algunas p\u00e1ginas mientras navega en la biblioteca.", + "EnableThemeVideos": "Habilitar videos de tema", + "EnableThemeVideosHelp": "Al habilitarse, los videos de tema ser\u00e1n reproducidos en el fondo mientras navega en la biblioteca.", + "RunAtStartup": "Ejecutar al iniciar", + "LabelScreensaver": "Protector de Pantalla:", + "LabelSoundEffects": "Efectos de Sonido:", + "LabelSkin": "Piel:", + "LabelName": "Nombre:", + "NewCollectionNameExample": "Ejemplo: Colecci\u00f3n Guerra de las Galaxias", + "MessageItemsAdded": "\u00cdtems agregados.", + "OptionNew": "Nuevo...", + "LabelPlaylist": "Lista de Reproducci\u00f3n:", + "AddToPlaylist": "Agregar a lista de reproducci\u00f3n", + "HeaderAddToPlaylist": "Agregar a Lista de Reproducci\u00f3n", + "Subtitles": "Subt\u00edtulos", + "LabelTheme": "Tema:", + "LabelDashboardTheme": "Tema del panel de control del Servidor:", + "SearchForSubtitles": "Buscar Subtitulos", + "LabelLanguage": "Idioma:", + "Search": "Buscar", + "NoSubtitleSearchResultsFound": "No se encontraron resultados.", + "File": "Archivo", + "MessageAreYouSureDeleteSubtitles": "\u00bfEst\u00e1 seguro de querer eliminar este archivo de subtitulos?", + "ConfirmDeletion": "Confirmar Eliminaci\u00f3n", + "MySubtitles": "Mis Subtitulos", + "MessageDownloadQueued": "Descargar cola.", + "EditSubtitles": "Editar subt\u00edtulos", + "UnlockGuide": "Desbloquear Gu\u00eda", + "RefreshMetadata": "Actualizar metadatos", + "ReplaceExistingImages": "Reemplazar im\u00e1genes existentes", + "ReplaceAllMetadata": "Remplazar todos los metadatos", + "SearchForMissingMetadata": "Buscar metadatos faltantes", + "LabelRefreshMode": "Modo de actualizaci\u00f3n:", + "NoItemsFound": "No se encontraron \u00edtems.", + "HeaderSaySomethingLike": "Decir Algo Como...", + "ButtonTryAgain": "Intentar de Nuevo", + "HeaderYouSaid": "Ha Dicho...", + "MessageWeDidntRecognizeCommand": "Lo sentimos, no reconocimos ese comando.", + "MessageIfYouBlockedVoice": "Si ha negado el acceso a la voz a la aplicaci\u00f3n necesitara reconfigurar antes de intentarlo de nuevo.", + "ValueDiscNumber": "Disco {0}", + "Unrated": "Sin clasificar", + "Favorite": "Favorito", + "Like": "Me gusta", + "Dislike": "No me gusta", + "RefreshDialogHelp": "Los metadatos son actualizados bas\u00e1ndose en las configuraciones y servicios de internet que que est\u00e9n activados en el panel de control de su Servidor de Emby.", + "Open": "Abrir", + "Play": "Reproducir", + "AddToPlayQueue": "Agregar a la cola de reproduccion", + "Shuffle": "Aleatorio", + "Identify": "Identificar", + "EditImages": "Editar im\u00e1genes", + "EditMetadata": "Editar metadatos", + "Convert": "Convertir", + "Sync": "Sincronizar", + "InstantMix": "Mix instant\u00e1neo", + "ViewAlbum": "Ver album", + "ViewArtist": "Ver artista", + "QueueAllFromHere": "Encolar todos desde aqu\u00ed", + "PlayAllFromHere": "Reproducir todos desde aqu\u00ed", + "PlayFromBeginning": "Reproducir desde el inicio", + "ResumeAt": "Reanudar desde {0}", + "RemoveFromPlaylist": "Eliminar de la lista de reproducci\u00f3n", + "RemoveFromCollection": "Remover de la colecci\u00f3n", + "Sort": "Ordenar", + "Trailer": "Trailer", + "MarkPlayed": "Marcar como Reproducido", + "MarkUnplayed": "Marcar como No Reproducido", + "GroupVersions": "Agrupar versiones", + "PleaseSelectTwoItems": "Por favor selecciona al menos dos \u00edtems.", + "TryMultiSelect": "Intente Multi-Selecci\u00f3n", + "TryMultiSelectMessage": "Para editar m\u00faltiples medios, solo de clic sostenido sobre cualquier p\u00f3ster y elija los items que desea administrar. \u00a1int\u00e9ntelo!", + "HeaderConfirmRecordingCancellation": "Confirmar Cancelaci\u00f3n de la Grabaci\u00f3n", + "MessageConfirmRecordingCancellation": "\u00bfcancelar esta grabaci\u00f3n?", + "Error": "Error", + "VoiceInput": "Entrada de Voz", + "LabelContentType": "Tipo de Contenido:", + "LabelPath": "Ruta:", + "Playlists": "Listas de reproducci\u00f3n", + "LabelTitle": "Titulo:", + "LabelOriginalTitle": "Titulo original:", + "LabelSortTitle": "Titulo para ordenar:", + "LabelDateAdded": "Fecha de adici\u00f3n:", + "DateAdded": "Fecha de adici\u00f3n", + "DatePlayed": "Fecha de reproducci\u00f3n", + "ConfigureDateAdded": "Configure como la fecha de adici\u00f3n es determinada en el Panel de Control del Servidor Emby bajo la configuraci\u00f3n de Bibliotecas", + "LabelStatus": "Estado:", + "LabelArtists": "Artistas:", + "LabelArtistsHelp": "Separar m\u00faltiples empleando:", + "HeaderAlbumArtists": "Artistas del \u00e1lbum", + "LabelAlbumArtists": "Artistas del \u00e1lbum:", + "LabelAlbum": "\u00c1lbum", + "Artists": "Artistas", + "ImdbRating": "Calificaci\u00f3n de IMDb", + "CommunityRating": "Calificaci\u00f3n de la comunidad", + "LabelCommunityRating": "Calificaci\u00f3n de la comunidad:", + "LabelCriticRating": "Calificaci\u00f3n de la cr\u00edtica:", + "CriticRating": "Calificaci\u00f3n de la cr\u00edtica", + "LabelWebsite": "Sitio web:", + "LabelTagline": "Eslogan", + "LabelOverview": "Sinopsis:", + "LabelShortOverview": "Sinopsis corta:", + "LabelReleaseDate": "Fecha de estreno:", + "LabelYear": "A\u00f1o:", + "LabelPlaceOfBirth": "Lugar de nacimiento:", + "Aired": "Transmitido", + "LabelAirDays": "Se emite los d\u00edas:", + "LabelAirTime": "Duraci\u00f3n:", + "LabelRuntimeMinutes": "Duraci\u00f3n (minutos):", + "LabelParentalRating": "Clasificaci\u00f3n parental:", + "LabelCustomRating": "Calificaci\u00f3n personalizada:", + "LabelOriginalAspectRatio": "Relaci\u00f3n de aspecto original:", + "Label3DFormat": "Formato 3D:", + "FormatValue": "Formato: {0}", + "DownloadsValue": "{0} descargas", + "PerfectMatch": "Coincidencia exacta", + "EnableExternalVideoPlayers": "Habilitar reproductores externos de video", + "EnableExternalVideoPlayersHelp": "Un men\u00fa de reproductor externo se mostrara cuando inicie la reproducci\u00f3n de un video.", + "HeaderSpecialEpisodeInfo": "Informaci\u00f3n del Episodio Especial", + "LabelAirsBeforeSeason": "Transmisi\u00f3n antes de la temporada:", + "LabelAirsAfterSeason": "Transmisi\u00f3n despu\u00e9s de la temporada:", + "LabelAirsBeforeEpisode": "Transmisi\u00f3n antes del episodio:", + "HeaderExternalIds": "IDs Externos:", + "HeaderDisplaySettings": "Configuraci\u00f3n de Pantalla", + "LabelDisplayOrder": "Orden para mostrar:", + "Display": "Pantalla", + "Countries": "Pa\u00edses", + "Genres": "G\u00e9neros", + "Studios": "Estudios", + "Tags": "Etiquetas", + "HeaderMetadataSettings": "Configuraci\u00f3n de metadatos", + "People": "Personas", + "LabelMetadataDownloadLanguage": "Lenguaje preferido para descargas:", + "LabelLockItemToPreventChanges": "Bloquear este \u00edtem para evitar cambios futuros", + "MessageLeaveEmptyToInherit": "Dejar vac\u00edo para heredar la configuraci\u00f3n del \u00edtem padre, o el valor global por omisi\u00f3n.", + "LabelCountry": "Pa\u00eds:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "A\u00f1o de nacimiento:", + "LabelBirthDate": "Fecha de Nacimiento:", + "LabelDeathDate": "Fecha de defunci\u00f3n:", + "LabelEndDate": "Fecha de Fin:", + "LabelSeasonNumber": "Temporada numero:", + "LabelEpisodeNumber": "Episodio numero:", + "LabelTrackNumber": "N\u00famero de Pista:", + "LabelNumber": "N\u00famero:", + "LabelDiscNumber": "N\u00famero de disco:", + "LabelParentNumber": "N\u00famero antecesor:", + "SortName": "Nombre para ordenar", + "ReleaseDate": "Fecha de estreno", + "Continuing": "Continuando", + "Ended": "Finalizado", + "HeaderEnabledFields": "Campos Habilitados", + "HeaderEnabledFieldsHelp": "Desmarcar un campo para bloquearlo y prevenir que sus datos cambien.", + "Backdrops": "Im\u00e1genes de fondo", + "Images": "Im\u00e1genes", + "Runtime": "Duraci\u00f3n", + "ProductionLocations": "Lugares de produccion", + "BirthLocation": "Lugar de nacimiento", + "ParentalRating": "Clasificaci\u00f3n Parental", + "PlayCount": "Cantidad de reproducciones", + "Name": "Nombre", + "Overview": "Sinopsis", + "LabelType": "Tipo:", + "LabelPersonRole": "Rol:", + "LabelPersonRoleHelp": "Ejemplo: Conductor de cami\u00f3n de helados", + "Actor": "Actor", + "Composer": "Compositor", + "Director": "Director", + "GuestStar": "Estrella invitada", + "Producer": "Productor", + "Writer": "Escritor", + "MessageNoSyncJobsFound": "No se han encontrado descargas. Cree descargas empleando los botones de Sincronizar en la app.", + "MessageNoDownloadsFound": "No hay elementos sin conexi\u00f3n. Descargue sus medios para usarlos sin conexion haciendo clic en Descargar trav\u00e9s de la app.", + "InstallingPackage": "Instalando {0}", + "PackageInstallCompleted": "{0} instalaci\u00f3n completada.", + "PackageInstallFailed": "{0} instalaci\u00f3n fallida.", + "PackageInstallCancelled": "{0} instalaci\u00f3n cancelada.", + "SeriesYearToPresent": "{0} - Actualidad", + "ValueOneItem": "1 \u00cdtem", + "ValueOneSong": "1 canci\u00f3n", + "ValueSongCount": "{0} canciones", + "ValueOneMovie": "1 pel\u00edcula", + "ValueMovieCount": "{0} pel\u00edculas", + "ValueOneSeries": "1 serie", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episodio", + "ValueEpisodeCount": "{0} episodios", + "ValueOneGame": "1 juego", + "ValueGameCount": "{0} juegos", + "ValueOneAlbum": "1 \u00e1lbum", + "ValueAlbumCount": "{0} \u00e1lbumes", + "ValueOneMusicVideo": "1 video musical", + "ValueMusicVideoCount": "{0} videos musicales", + "ValueMinutes": "{0} min", + "Albums": "\u00c1lbumes", + "Songs": "Canciones", + "Books": "Libros", + "HeaderAudioBooks": "Audio Libros", + "HeaderIdentifyItemHelp": "Introduzca uno o m\u00e1s criterios de b\u00fasqueda. Elimine criterios para expandir los resultados.", + "PleaseEnterNameOrId": "Por favor introduzca un nombre o id externo.", + "MessageItemSaved": "\u00cdtem guardado.", + "SearchResults": "Resultados de la b\u00fasqueda", + "ServerNameIsRestarting": "El Servidor Emby - {0} se esta reiniciando.", + "ServerNameIsShuttingDown": "El Servidor Emby - {0} se esta apagando.", + "HeaderDeleteItems": "Borrar items", + "ConfirmDeleteItems": "Al borrar estos items ser\u00e1n eliminados tanto del sistema de archivos como de la biblioteca de medios. \u00bfEsta seguro que desea continuar?", + "PleaseRestartServerName": "Por favor reinicie el Servidor Emby - {0}.", + "LabelSyncJobName": "Nombre del trabajo de sincronizaci\u00f3n:", + "SyncingDots": "Sincronizando...", + "ConvertingDots": "Convirtiendo...", + "LabelQuality": "Calidad:", + "LabelSyncNoTargetsHelp": "Parece que actualmente no cuentas con ninguna app que soporte descargas sin conexi\u00f3n.", + "DownloadingDots": "Descargando...", + "HeaderSyncRequiresSub": "Descargar requiere de una suscripci\u00f3n activa de Emby Premiere", + "LearnMore": "Aprenda m\u00e1s", + "LabelProfile": "Perf\u00edl:", + "LabelBitrateMbps": "Tasa de bits (Mbps):", + "ConvertUnwatchedVideosOnly": "Convertir \u00f9nicamente videos no vistos", + "SyncUnwatchedVideosOnly": "Descargar \u00fanicamente videos no vistos", + "ConvertUnwatchedVideosOnlyHelp": "Solo los videos no vistos ser\u00e1n convertidos.", + "SyncUnwatchedVideosOnlyHelp": "Solamente los videos a\u00fan no vistos ser\u00e1n descargados, se eliminar\u00e1n los videos del dispositivo conforme \u00e9stos sean vistos.", + "AutomaticallySyncNewContent": "Descargar autom\u00e1ticamente nuevos contenidos", + "AutomaticallySyncNewContentHelp": "Los contenidos nuevos agregados a esta carpeta ser\u00e1n descargados autom\u00e1ticamente al dispositivo.", + "AutomaticallyConvertNewContent": "Convertir contenidos nuevos autom\u00e1ticamente", + "AutomaticallyConvertNewContentHelp": "Los contenidos nuevos agregados a esta carpeta ser\u00e1n convertidos autom\u00e1ticamente.", + "LabelItemLimit": "L\u00edmite de \u00cdtems:", + "ConvertItemLimitHelp": "Opcional. Establecer un l\u00edmite en el n\u00famero de \u00edtems que ser\u00e1n convertidos.", + "DownloadItemLimitHelp": "Opcional. Establecer un l\u00edmite en el n\u00famero de \u00edtems que ser\u00e1n descargados.", + "PleaseSelectDeviceToSyncTo": "Por favor seleccione un dispositivo con al que desee descargar.", + "Screenshots": "Capturas de pantalla", + "MoveRight": "Mover a la derecha", + "MoveLeft": "Mover a la izquierda", + "ConfirmDeleteImage": "\u00bfEliminar imagen?", + "HeaderEditImages": "Editar im\u00e1genes", + "Settings": "Configuraci\u00f3n", + "ShowIndicatorsFor": "Mostrar indicadores para:", + "NewEpisodes": "Episodios nuevos", + "Episodes": "Episodios", + "HDPrograms": "Programas en HD", + "Programs": "Programas", + "LiveBroadcasts": "Transmisiones en vivo", + "Premieres": "Estrenos", + "RepeatEpisodes": "Repetir episodios", + "DvrSubscriptionRequired": "Emby DVR necesita una suscripci\u00f3n activa de Emby Premiere.", + "HeaderCancelRecording": "Cancelar Grabaci\u00f3n", + "CancelRecording": "Cancelar grabaci\u00f3n", + "HeaderKeepRecording": "Conservar Grabaciones", + "HeaderCancelSeries": "Cancelar Serie", + "HeaderKeepSeries": "Conservar Serie", + "HeaderLearnMore": "Aprenda m\u00e1s", + "DeleteMedia": "Eliminar medios", + "SeriesSettings": "Configuraci\u00f3n de la Serie", + "HeaderRecordingOptions": "Opciones de Grabaci\u00f3n", + "CancelSeries": "Cancelar serie", + "DoNotRecord": "No grabar", + "HeaderSeriesOptions": "Opciones de Serie", + "LabelChannels": "Canales:", + "ChannelNameOnly": "Canal {0} solamente", + "Anytime": "En cualquier momento", + "AnyLanguage": "Cualquier lenguaje", + "AroundTime": "Alrededor de {0}", + "All": "Todo", + "AllChannels": "Todos los canales", + "LabelRecord": "Grabar:", + "NewEpisodesOnly": "Solo episodios nuevos", + "AllEpisodes": "Todos los episodios", + "LabelStartWhenPossible": "Iniciar cuando sea posible:", + "LabelStopWhenPossible": "Detener cuando sea posible:", + "MinutesBefore": "Minutos antes", + "MinutesAfter": "minutos despues", + "SkipEpisodesAlreadyInMyLibrary": "No grabar episodios que ya se encuentran en mi biblioteca", + "SkipEpisodesAlreadyInMyLibraryHelp": "Los episodios ser\u00e1n comparados usando el numero de temporada y de episodio, cuando est\u00e9n disponibles.", + "LabelKeepUpTo": "Mantener hasta:", + "AsManyAsPossible": "Tantos como sea posible", + "DefaultErrorMessage": "Ha ocurrido un error al procesar la solicitud. Por favor int\u00e9ntelo de nuevo mas tarde.", + "LabelKeep:": "Mantener:", + "UntilIDelete": "Hasta que yo lo borre", + "UntilSpaceNeeded": "Hasta que se necesite espacio", + "Categories": "Categor\u00edas", + "Sports": "Deportes", + "News": "Noticias", + "Movies": "Pel\u00edculas", + "Kids": "Ni\u00f1os", + "EnableColorCodedBackgrounds": "Habilitar fondos con c\u00f3digo de color", + "SortChannelsBy": "Ordenar canales por:", + "RecentlyWatched": "Visto recientemente", + "ChannelNumber": "Numero de canal", + "HeaderBenefitsEmbyPremiere": "Beneficios de Emby Premier", + "ThankYouForTryingEnjoyOneMinute": "Por favor disfrute de un minuto de reproducci\u00f3n. Gracias por probar Emby.", + "HeaderTryPlayback": "Intente Reproducir", + "HowDidYouPay": "\u00bfCual sera su forma de pago?", + "IHaveEmbyPremiere": "Ya cuento con Emby Premiere", + "IPurchasedThisApp": "Ya he comprado esta app", + "ButtonRestorePreviousPurchase": "Restaurar Compra", + "ButtonUnlockWithPurchase": "Desbloquear con una Compra", + "ButtonUnlockPrice": "Desbloquear {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premier Mensual {0}", + "HeaderAlreadyPaid": "\u00bfYa ha pagado?", + "ButtonPlayOneMinute": "Reproducir un minuto", + "PlaceFavoriteChannelsAtBeginning": "Colocar canales favoritos al inicio", + "HeaderUnlockFeature": "Desbloquear Caracter\u00edstica", + "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", + "Items": "\u00cdtems", + "OneChannel": "Un canal", + "ConfirmRemoveDownload": "\u00bfEliminar descarga?", + "RemoveDownload": "Eliminar descarga", + "KeepDownload": "Seguir descargando", + "AddedOnValue": "Agregado {0}", + "RemovingFromDevice": "Eliminando del dispositivo", + "KeepOnDevice": "Conservar en el dispositivo", + "CancelDownload": "Cancelar descarga", + "SyncJobItemStatusReadyToTransfer": "Listo para Transferir", + "SyncJobItemStatusSyncedMarkForRemoval": "Eliminando del dispositivo", + "SyncJobItemStatusQueued": "En cola", + "SyncJobItemStatusConverting": "Convirtiendo", + "SyncJobItemStatusTransferring": "Transfiriendo", + "SyncJobItemStatusSynced": "Descargado", + "SyncJobItemStatusFailed": "Fall\u00f3", + "SyncJobItemStatusRemovedFromDevice": "Eliminado del dispositivo", + "SyncJobItemStatusCancelled": "Cancelado", + "Retry": "Volver a intentar", + "HeaderMyDevice": "Mi Dispositivo", + "Continue": "Continuar", + "ContinueInSecondsValue": "Continua en {0} segundos.", + "HeaderRemoteControl": "Control Remoto", + "Disconnect": "Desconectar", + "EnableDisplayMirroring": "Habilitar duplicaci\u00f3n de pantalla", + "HeaderPlayOn": "Reproducir En", + "Quality": "Calidad", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "Para restaurar su compra previa, por favor aseg\u00farese de que se encuentra registrado en el dispositivo con la misma cuenta de Google (o Amazon) con que hizo la compra. Aseg\u00farese que la tienda de aplicaciones esta habilitada, no esta restringida por cualquier control parental y que tiene una conexi\u00f3n de internet activa. Esto se tiene que hacer solo una vez para restaurar su compra previa.", + "AspectRatio": "Relaci\u00f3n de aspecto", + "Original": "Original", + "Fill": "Llenar", + "BestFit": "Mejor ajuste", + "MessageNoServersAvailableToConnect": "No hay servidores disponibles para conectarse. Si se le ha invitado a compartir un servidor, aseg\u00farese de aceptarlo aqu\u00ed abajo o haciendo clic en la liga del correo electr\u00f3nico.", + "MessagePlayAccessRestricted": "La reproducci\u00f3n de este contenido se encuentra restringida actualmente. Por favor contacte a su administrador del Servidor Emby para mas informaci\u00f3n.", + "Accept": "Aceptar", + "Reject": "Rechazar", + "Connect": "Conectar", + "HeaderMyMedia": "Mis Medios", + "HeaderMyMediaSmall": "Mis medios (peque\u00f1o)", + "LatestFromLibrary": "M\u00e1s recientes {0}", + "ContinueWatching": "Continuar viendo", + "HeaderLatestChannelMedia": "\u00cdtems Recientes de Canales", + "HeaderContinueWatching": "Continuar Viendo", + "HeaderContinueListening": "Continuar Escuchando", + "HeaderActiveRecordings": "Grabaciones Activas", + "HeaderLatestRecordings": "Grabaciones Recientes", + "LabelSyncTo": "Sincronizar con:", + "LabelConvertTo": "Convertir a:", + "Next": "Siguiente", + "LabelSource": "Fuente:", + "LabelVersion": "Versi\u00f3n:", + "AllLanguages": "Todos los idiomas", + "Previous": "Anterior", + "HeaderNextUp": "A Continuaci\u00f3n", + "HeaderLatestFrom": "M\u00e1s recientes desde {0}", + "LabelHomeScreenSectionValue": "Pagina de inicio secci\u00f3n {0}:", + "SettingsSaved": "Configuraci\u00f3n guardada.", + "None": "Ninguno", + "More": "Mas", + "Up": "Arriba", + "Down": "Abajo", + "Home": "Inicio", + "Favorites": "Favoritos", + "HeaderHomeScreen": "Pantalla de Inicio", + "HeaderLatestChannelItems": "\u00cdtems Recientes de Canales", + "HeaderLibraryOrder": "Orden de Bibliotecas", + "HideWatchedContentFromLatestMedia": "Ocultar contenido ya visto de Agregadas Recientemente", + "HeaderOnNow": "Transmiti\u00e9ndo Ahora", + "HeaderPlaybackError": "Error de Reproducci\u00f3n", + "PlaybackErrorNotAllowed": "Actualmente no esta autorizado para reproducir este contenido. Por favor contacte a su administrador de sistema para mas informaci\u00f3n.", + "PlaybackErrorNoCompatibleStream": "No hay streams compatibles en este en este momento. Por favor intente de nuevo mas tarde o contacte a su administrador de sistema para mas detalles.", + "PlaybackErrorPlaceHolder": "Por favor introduzca el disco para poder reproducir este video.", + "Guide": "Gu\u00eda", + "Suggestions": "Sugerencias", + "HeaderFavoriteCollections": "Colecciones Favoritas", + "HeaderFavoritePlaylists": "Listas de Reproducci\u00f3n Favoritas", + "Collections": "Colecciones", + "LabelSelectFolderGroups": "Agrupar autom\u00e1ticamente el contenido de las siguientes carpetas en vistas tales como Pel\u00edculas, M\u00fasica y TV:", + "LabelSelectFolderGroupsHelp": "Las carpetas sin marcar ser\u00e1n mostradas individualmente en su propia vista.", + "Folders": "Carpetas", + "DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla de inicio como Recientes o Continua Viendo", + "DisplayInMyMedia": "Mostrar en pantalla de inicio", + "Shows": "Programas", + "HeaderLibraryFolders": "Carpetas de Biblioteca", + "HeaderTermsOfPurchase": "T\u00e9rminos de Compra", + "PrivacyPolicy": "Pol\u00edtica de privacidad", + "TermsOfUse": "T\u00e9rminos de uso", + "RepeatMode": "Modo de repeticion", + "RepeatOne": "Repetir uno", + "RepeatAll": "Repetir todas", + "LabelDefaultScreen": "Pantalla por defecto:", + "ConfirmEndPlayerSession": "\u00bfDesea cerrar Emby en {0}?", + "Yes": "S\u00ed", + "No": "No", + "LiveTV": "TV en Vivo", + "Schedule": "Programacion", + "Recordings": "Grabaciones", + "MarkWatched": "Marcar como Visto", + "ScanForNewAndUpdatedFiles": "Buscar archivos nuevos y actualizados", + "DirectStreamHelp1": "El medio es compatible con el dispositivo en cuanto a la resoluci\u00f3n y tipo de medio (H.264, AC3, etc.), pero es un es un contenedor de archivo incompatible (.mkv, .avi, .wmv, etc.). El video sera re empaquetado al vuelo antes de transmitirlo al dispositivo.", + "DirectStreamHelp2": "La Transmisi\u00f3n Directa de un archivo usa muy poco poder de procesamiento sin ninguna perdida en la calidad de video.", + "MediaIsBeingConverted": "Los medios est\u00e1n siendo convertidos a un formato compatible con el dispositivo que esta reproduciendo el medio.", + "StatsForNerds": "Estad\u00edsticas para los nerds", + "LabelReasonForTranscoding": "Motivo para transcodificar:", + "DirectPlaying": "Reproducci\u00f3n directa", + "DirectStreaming": "Transmisi\u00f3n Directa", + "Transcoding": "Transcodificando", + "ContainerBitrateExceedsLimit": "La tasa de bits de este medio excede el limite.", + "VideoCodecNotSupported": "Codec de video no soportado", + "AudioCodecNotSupported": "Codec de audio no soportado", + "SubtitleCodecNotSupported": "Formato de subtitulo no soportado", + "DirectPlayError": "Error de reproducci\u00f3n directa", + "ContainerNotSupported": "Contenedor no soportado", + "VideoLevelNotSupported": "Nivel de video no soportado", + "AudioBitrateNotSupported": "Tasa de bits de audio no soportado", + "AudioChannelsNotSupported": "Canales de audio no soportados", + "VideoResolutionNotSupported": "Resoluci\u00f3n de video no soportada", + "AudioProfileNotSupported": "Perfil de audio no soportado", + "AudioSampleRateNotSupported": "Muestreo (sample) de audio no soportado", + "AnamorphicVideoNotSupported": "Video anamorfico no soportado", + "InterlacedVideoNotSupported": "Video entrelazado no soportado", + "SecondaryAudioNotSupported": "Cambio de pista de audio no soportado", + "ErrorRemovingEmbyConnectAccount": "Hubo un error retirando la cuenta de Emby Connect. Por favor aseg\u00farese que su conexi\u00f3n a internet esta activa e intente de nuevo.", + "HeaderEmbyAccountRemoved": "Cuenta Emby Eliminada", + "MessageEmbyAccontRemoved": "La cuenta Emby ha sido eliminada de este usuario.", + "HeaderInvitationSent": "Invitaci\u00f3n Enviada", + "MessageInvitationSentToUser": "Se ha enviado un correo electr\u00f3nico a {0}, invit\u00e1ndolo a aceptar tu invitaci\u00f3n para compartir.", + "MessageInvitationSentToNewUser": "Un correo electr\u00f3nico se ha enviado a {0} invit\u00e1ndolos a registrarse en Emby.", + "GuestUserNotFound": "Usuario no encontrado. Por favor aseg\u00farese de que el nombre es correcto e intente de nuevo, o intente introducir la direcci\u00f3n de correo de su invitado.", + "ErrorReachingEmbyConnect": "Hubo un error al tratar de contactar el servidor de Emby Connect. Por favor aseg\u00farese de que tiene una conexi\u00f3n activa de internet e intente de nuevo.", + "ErrorAddingEmbyConnectAccount1": "Hubo un error agregando la cuenta de Emby Connect. \u00bfYa ha creado una cuenta de Emby? Registrese en {0}.", + "ErrorAddingEmbyConnectAccount2": "Si continua teniendo problemas, por favor env\u00ede un correo electr\u00f3nico a {0} desde la direcci\u00f3n de correo electr\u00f3nico usada con la cuenta Emby.", + "ErrorAddingGuestAccount1": "Hubo un error agregando la cuenta de Emby Connect. \u00bfSu invitado ya ha creado una cuenta de Emby Connect? Puede registrarse en {0}.", + "ErrorAddingGuestAccount2": "Si continua teniendo problemas, escriba un correo electr\u00f3nico a {0}, e incluya su direcci\u00f3n de correo electr\u00f3nico ademas de la de su invitado.", + "MessageEmbyAccountAdded": "La cuenta Emby ha sido agregada a este usuario.", + "MessagePendingEmbyAccountAdded": "La cuenta Emby ha sido agregada a este usuario. Se enviara un correo electr\u00f3nico al propietario de la cuenta. La invitaci\u00f3n necesitara ser confirmada dando clic al enlace dentro del correo electr\u00f3nico.", + "HeaderEmbyAccountAdded": "Cuenta Emby Agregada", + "LabelSubtitlePlaybackMode": "Modo de subt\u00edtulo:", + "ErrorDeletingItem": "Hubo un error eliminando el \u00edtem del Servidor Emby. Por favor verifique tenga permisos de escritura en la carpeta de medios e intente de nuevo.", + "NoSubtitles": "Sin Subtitulos", + "Default": "Por defecto", + "Absolute": "Absoluto", + "Smart": "Inteligente", + "Small": "Peque\u00f1o", + "Smaller": "M\u00e1s peque\u00f1o", + "Medium": "Mediano", + "Large": "Grande", + "ExtraLarge": "Extra grande", + "OnlyForcedSubtitles": "\u00danicamente subt\u00edtulos forzados", + "AlwaysPlaySubtitles": "Siempre mostrar subt\u00edtulos", + "DefaultSubtitlesHelp": "Los subtitulos son cargados basados en los indicadores \"por defecto\" y \"forzado\" incluidos en los metadatos. Las preferencias de idioma son consideradas cuando hay m\u00faltiples opciones disponibles.", + "SmartSubtitlesHelp": "Los subt\u00edtulos que coincidan con el lenguaje preferido ser\u00e1n cargados cuando el audio se encuentre en un lenguaje extranjero.", + "HeaderSubtitleSettings": "Configuraci\u00f3n de Subtitulos", + "HeaderSubtitleAppearance": "Apariencia de Subtitulos", + "OnlyForcedSubtitlesHelp": "Se cargar\u00e1n \u00fanicamente subt\u00edtulos marcados como forzados.", + "AlwaysPlaySubtitlesHelp": "Los subt\u00edtulos que coincidan con el lenguaje preferido ser\u00e1n cargados independientemente del lenguaje del audio.", + "NoSubtitlesHelp": "Los subt\u00edtulos no ser\u00e1n cargados por defecto. Pero pueden ser activados manualmente durante la reproducci\u00f3n.", + "LabelPreferredSubtitleLanguage": "Idioma preferido para subtitulos:", + "LabelTextSize": "Tama\u00f1o de texto:", + "TheseSettingsAffectSubtitlesOnThisDevice": "Estas configuraciones solo afectan subtitulo de este dispositivo", + "LabelDropShadow": "Mostrar sombra:", + "LabelTextBackgroundColor": "Color de fondo para el texto:", + "LabelWindowBackgroundColor": "Color de fondo para el texto:", + "LabelFont": "Fuente:", + "LabelTextColor": "Color de texto:", + "Raised": "Elevacion", + "Depressed": "Depresi\u00f3n", + "Uniform": "Uniforme", + "DropShadow": "Mostrar sombra", + "SmallCaps": "May\u00fasculas peque\u00f1as", + "SubtitleAppearanceSettingsDisclaimer": "Estas configuraciones no se aplicaran a subtitulos gr\u00e1ficos (PGS, DVD, etc.) o a subtitulos que tienen sus propias fuentes embebidas (ASS\/SSA).", + "LabelBurnSubtitles": "Subtitulos quemados:", + "OnlyImageFormats": "Solo formato de imagen (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determina si el servidor deber\u00eda quemar los subtitulos al convertir el video dependiendo en el formato de los subtitulos. Evitar los subtitulos quemados mejorara el rendimiento del servidor. Elija \"Auto\" para quemar los formatos basados en im\u00e1genes (por ejemplo VOBSUB, PGS, SUB\/IDX, etc.) as\u00ed como ciertos subtitulos ASS\/SSA", + "AllComplexFormats": "Todos los subtitulos complejos (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Estos ajustes tambi\u00e9n aplican a cualquier reproducci\u00f3n de Chromecast iniciada por este dispositivo.", + "HeaderWaitingForWifi": "Esperando Wifi", + "WifiRequiredToDownload": "Se necesita de una conexi\u00f3n Wifi para continuar descargando.", + "HeaderDownloadSettings": "Configuraci\u00f3n de Descargas", + "Hide": "Ocultar", + "HeaderStartNow": "Iniciar Ahora", + "HeaderNextVideoPlayingInValue": "El Siguiente Video se Reproducir\u00e1 en {0}", + "HeaderNextEpisodePlayingInValue": "El Siguiente Episodio se Reproducir\u00e1 en {0}", + "HeaderSecondsValue": "{0} Segundos", + "AudioBitDepthNotSupported": "Profundidad de bits de Audio no soportado", + "VideoProfileNotSupported": "Perfil de video no soportado", + "VideoFramerateNotSupported": "Tasa de Cuadros por Segundo del video no soportado", + "VideoBitDepthNotSupported": "Profundidad de bits de Video no soportado", + "RefFramesNotSupported": "Cantidad de cuadros de referencia del Video no soportado", + "ErrorConnectServerUnreachable": "Hubo un error al ejecutar la operaci\u00f3n solicitada. Su servidor no puede contactar nuestro servidor de Emby Connect en {0}. Por favor aseg\u00farese de que su servidor tiene una conection a internet activa y que el firewall o software de seguridad permita la comunicaci\u00f3n.", + "StopRecording": "Detener grabaci\u00f3n", + "HeaderStopRecording": "Detener Grabaci\u00f3n", + "ManageRecording": "Administrar grabaciones", + "LabelDropImageHere": "Arrastre la imagen aqu\u00ed, o de clic para navegar.", + "MessageFileReadError": "Hubo un error al leer el archivo. Por favor intente de nuevo.", + "Browse": "Navegar", + "HeaderUploadImage": "Subir Imagen", + "HeaderAddUpdateImage": "Agregar\/Actualizar Imagen", + "LabelImageType": "Tipo de imagen:", + "Upload": "Subir", + "Primary": "Principal", + "Art": "Arte", + "Backdrop": "Imagen de Fondo", + "Banner": "Cart\u00e9l", + "Box": "Caja", + "BoxRear": "Reverso de caja", + "Disc": "DIsco", + "Logo": "Logotipo", + "Menu": "Men\u00fa", + "Screenshot": "Captura de pantalla", + "Thumb": "Miniatura", + "ValueSeconds": "{0} segundos", + "HeaderAudioSettings": "Configuraci\u00f3n de Audio", + "LabelAudioLanguagePreference": "Idioma preferido de audio:", + "LabelPlayDefaultAudioTrack": "Reproducir la pista de audio por defecto independientemente del lenguaje", + "HeaderVideoQuality": "Calidad de Video", + "CinemaModeConfigurationHelp": "El modo cine trae la experiencia del cine directo al la sala de TV con la habilidad de reproducir tr\u00e1ilers e intros personalizados antes de la presentaci\u00f3n estelar.", + "EnableNextVideoInfoOverlay": "Habilitar ver la informaci\u00f3n del siguiente video durante la reproducci\u00f3n", + "EnableNextVideoInfoOverlayHelp": "Al finalizar un video, mostrar informaci\u00f3n sobre el siguiente video a reproducir en la lista de reproducci\u00f3n.", + "PlayNextEpisodeAutomatically": "Reproducir el siguiente episodio autom\u00e1ticamente", + "LabelMaxChromecastBitrate": "Tasa maxima de bits para El Chromecast:", + "LabelSkipBackLength": "Longitud de salto hacia atr\u00e1s:", + "LabelSkipForwardLength": "Longitud de salto hacia adelante:", + "EnableCinemaMode": "Activar modo cine", + "LabelInternetQuality": "Calidad en internet:", + "HeaderMusicQuality": "Calidad de Musica", + "LabelHomeNetworkQuality": "Calidad en Red Local:", + "HeaderLatestMedia": "Agregadas Recientemente", + "HeaderRestartingEmbyServer": "Reiniciando el Servidor Emby", + "RestartPleaseWaitMessage": "Por favor espere mientras el Servidor Emby cierra y reinicia. Este puede tomar un minuto o dos.", + "PlayNext": "Reproducir siguiente", + "AllowSeasonalThemes": "Permitir temas de temporada autom\u00e1ticamente", + "AllowSeasonalThemesHelp": "Si esta habilitado, temas de temporada reemplazaran ocasionalmente el tema por defecto.", + "AutoBasedOnLanguageSetting": "Auto (basado en la configuraci\u00f3n del lenguaje)", + "LabelDateTimeLocale": "Configuraci\u00f3n regional de Fecha y Hora:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directores: {0}", + "GenreValue": "Genero: {0}", + "GenresValue": "G\u00e9neros: {0}", + "LinksValue": "Enlaces: {0}", + "TagsValue": "Etiquetas: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subt\u00edtulos:", + "Off": "Apagar", + "ShowTitle": "Mostrar titulo", + "ShowYear": "Mostrar a\u00f1o", + "Filters": "Filtros", + "Unplayed": "No reproducido", + "LabelTVHomeScreen": "Modo de pantalla de TV:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Agrupar por series", + "HeaderVideoType": "Tipo de Video", + "HeaderSeriesStatus": "Estado de la Serie", + "Features": "Caracter\u00edsticas", + "Trailers": "Tr\u00e1ilers", + "Extras": "Extras", + "ThemeSongs": "Canciones de Tema", + "ThemeVideos": "Videos de Tema", + "HeaderFavoriteMovies": "Pel\u00edculas Favoritas", + "HeaderFavoriteShows": "Programas Favoritos", + "HeaderFavoriteEpisodes": "Episodios Favoritos", + "HeaderFavoriteVideos": "Videos Favoritos", + "HeaderFavoriteGames": "Juegos Favoritos", + "HeaderFavoriteArtists": "Artistas Favoritos", + "HeaderFavoriteAlbums": "\u00c1lbumes Favoritos", + "HeaderFavoriteSongs": "Canciones Favoritas", + "Ascending": "Ascendente", + "Descending": "Descendente", + "ColorPrimaries": "Colores primarios", + "ColorSpace": "Espacio de color", + "ColorTransfer": "Transferencia de color", + "VideoRange": "Rango de video", + "SeriesDisplayOrderHelp": "Ordenar los episodios por fecha transmisi\u00f3n, orden del dvd o por su numeraci\u00f3n absoluta.", + "PlaybackSettingsIntro": "Para configurar las opciones de reproducci\u00f3n predeterminadas, detenga la reproducci\u00f3n de video. entonces de clic en su icono de usuario en la esquina superior derecha de la aplicaci\u00f3n.", + "SubtitleSettingsIntro": "Para configurar la apariencia predeterminada de los subtitulos e idioma, detenga la reproducci\u00f3n de video, entonces de clic en su icono de usuario en la parte superior derecha de la aplicaci\u00f3n." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/es.json b/src/bower_components/emby-webcomponents/strings/es.json index 31c35bf32d..2630b061ec 100644 --- a/src/bower_components/emby-webcomponents/strings/es.json +++ b/src/bower_components/emby-webcomponents/strings/es.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Aceptar", - "AccessRestrictedTryAgainLater": "El acceso está restringido actualmente. Por favor inténtalo más tarde.", - "Actor": "Actor", - "Add": "Añadir", - "AddToCollection": "Añadir a la colección", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Añadir a la lista de reproducción", - "AddedOnValue": "Añadido {0}", - "Advanced": "Avanzado", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Álbumes", - "All": "Todo", - "AllChannels": "Todos los canales", - "AllComplexFormats": "Todos los formatos complejos (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Todos los episodios", - "AllLanguages": "Todos los idiomas", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Mostrar siempre subtítulos", - "AlwaysPlaySubtitlesHelp": "Los subtítulos que concuerden con la preferencia de idioma se cargarán independientemente del idioma de audio.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Arte", - "Artists": "Artistas", - "AsManyAsPossible": "Tantos como sea posible", - "Ascending": "Ascending", - "AspectRatio": "Relación de aspecto", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "Nuevo", - "AudioBitDepthNotSupported": "Profundidad de bits de audio no soportada", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Canales de audio no soportados", - "AudioCodecNotSupported": "Codec de audio no soportado", - "AudioProfileNotSupported": "Perfil de audio no soportado", - "AudioSampleRateNotSupported": "Frecuencia de muestreo de audio no soportada", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Descargar automáticamente contenido nuevo", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Imagen de fondo", - "Backdrops": "Imágenes de fondo", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Lugar de nacimiento", - "Books": "Libros", - "Box": "Caja", - "BoxRear": "Caja (trasera)", - "Browse": "Navegar", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Cancelar", - "ButtonGotIt": "Lo tengo", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Reproducir un minuto", - "ButtonRestart": "Reiniciar", - "ButtonRestorePreviousPurchase": "Recuperar compra", - "ButtonTryAgain": "Inténtalo de nuevo", - "ButtonUnlockPrice": "Desbloquear {0}", - "ButtonUnlockWithPurchase": "Desbloquear con una compra", - "CancelDownload": "Cancelar descarga", - "CancelRecording": "Cancelar grabación", - "CancelSeries": "Cancelar series", - "Categories": "Categorías", - "ChannelNameOnly": "Canal {0} solo", - "ChannelNumber": "Número de canal", - "CinemaModeConfigurationHelp": "El modo cine proporciona la experiencia del cine directamente en su sala de estar con la capacidad de reproducir trailers e introducciones personalizadas antes de la función principal.", - "CinemaModeFeatureDescription": "El Modo Cine te da la verdadera experiencia de cine con tráilers e intros personalizadas antes de la función principal.", - "CloudSyncFeatureDescription": "Sincroniza tus medios en la nube para una copia de seguridad, archivado y conversión fácil.", - "Collections": "Colecciones", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Compositor", - "ConfigureDateAdded": "Configura como la fecha añadida se determina en el Panel de Control del servidor Jellyfin en los ajustes de la biblioteca.", - "ConfirmDeleteImage": "Borrar imagen", - "ConfirmDeleteItem": "Al borrar este ítem se borrará del sistema de archivos y de la biblioteca. ¿Quieres continuar?", - "ConfirmDeleteItems": "Al borrar este ítem se borrará del sistema de archivos y de la biblioteca. ¿Quieres continuar?", - "ConfirmDeletion": "Confirmar borrado", - "ConfirmEndPlayerSession": "¿Quieres cerrar Jellyfin en el dispositivo?", - "ConfirmRemoveDownload": "¿Quieres eliminar la descarga?", - "Connect": "Conectar", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Contenedor no soportado", - "Continue": "Continuar", - "ContinueInSecondsValue": "Continuar en {0} segundos", - "ContinueWatching": "Continue watching", - "Continuing": "Continuando", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Países", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Días", - "Default": "Por defecto", - "DefaultErrorMessage": "Ha habido un error procesando la solicitud. Por favor inténtalo más tarde.", - "DefaultSubtitlesHelp": "Los subtítulos se activan en función de los ajustes por defecto y etiquetas en los metadatos integrados. Los ajustes de idioma se tienen en cuenta cuando hay varias opciones disponibles.", - "Delete": "Borrar", - "DeleteMedia": "Eliminar medios", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Escritorio", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Reproducción directa", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Streaming directo", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disco", - "Disconnect": "Desconectar", - "Dislike": "No me gusta", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Seleccione el tipo de pantalla que está ejecutando Jellyfin.", - "DoNotRecord": "No grabar", - "Down": "Abajo", - "Download": "Descargar", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Descargado", - "Downloading": "Descargando", - "DownloadingDots": "Descargando", - "Downloads": "Descargas", - "DownloadsValue": "Descargas: {0}", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Editar", - "EditImages": "Editar imágenes", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Editar subtítulos", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Activar modo cine", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Activar mirroring de la pantalla", - "EnableExternalVideoPlayers": "Activar reproductores externos", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Activar la información del siguiente video durante la reproducción", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Habilitar temas videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Finalizado", - "EndsAtValue": "Termina a las {0}", - "Episodes": "Episodios", - "Error": "Error", - "ErrorAddingGuestAccount1": "Se ha producido un error al agregar la cuenta Jellyfin Connect. ¿Ha creado su invitado una cuenta de Jellyfin? Pueden registrarse en {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "Ha habido un error añadiendo la cuenta de Jellyfin Connect. ¿Te has creado una cuenta de Jellyfin primero? Regístrate en {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "Ha habido un error accediendo al servidor Jellyfin Connect. Por favor, asegúrate de que tienes conexión a internet e inténtalo de nuevo.", - "ErrorRemovingJellyfinConnectAccount": "Ha habido un error quitando la cuenta de Jellyfin Connect. Por favor asegúrate de que tienes una conexión a internet activa e inténtalo otra vez.", - "ExtraLarge": "Extragrande", - "Extras": "Extras", - "Favorite": "Favorito", - "Favorites": "Favoritos", - "FeatureRequiresJellyfinPremiere": "Esta característica necesita una suscripción a Jellyfin Premiere.", - "Features": "Features", - "File": "Archivo", - "Fill": "Llenar", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Formato: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Viernes", - "GenreValue": "Genre: {0}", - "Genres": "Géneros", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Agrupar versiones", - "GuestStar": "Estrella invitada", - "GuestUserNotFound": "Usuario no encontrado. Asegúrese de que el nombre es correcto y vuelva a intentarlo o intente ingresar su dirección de correo electrónico.", - "Guide": "Guía", - "HDPrograms": "Programas en HD", - "HeaderActiveRecordings": "Grabaciones activas", - "HeaderAddToCollection": "Agregar a la colección", - "HeaderAddToPlaylist": "Añadir a la lista", - "HeaderAddUpdateImage": "Añadir/Actualizar imagen", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "¿Ya has pagado?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audiolibros", - "HeaderAudioSettings": "Ajustes de audio", - "HeaderBecomeProjectSupporter": "Consigue Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Beneficios de Jellyfin Premiere", - "HeaderCancelRecording": "Cancelar Grabación", - "HeaderCancelSeries": "Cancelar Series", - "HeaderCinemaMode": "Modo cine", - "HeaderCloudSync": "Sincronización en la nube", - "HeaderConfirmRecordingCancellation": "Confirmar la cancelación de la grabación", - "HeaderContinueListening": "Continuar escuchando", - "HeaderContinueWatching": "Continuar viendo", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Borrar elemento", - "HeaderDeleteItems": "Borrar ítems", - "HeaderDisplaySettings": "Opciones de pantalla", - "HeaderDownloadSettings": "Ajustes de descargas", - "HeaderEditImages": "Editar Imágenes", - "HeaderEnabledFields": "Campos activados", - "HeaderEnabledFieldsHelp": "Desmarca un campo para bloquearlo y evitar que se cambie su contenido.", - "HeaderExternalIds": "Ids externos:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Apps de Jellyfin gratuitas", - "HeaderHomeScreen": "Pantalla de inicio", - "HeaderIdentifyItemHelp": "Asigna uno o más criterios de búsqueda. Quita criterios para aumentar el número de resultados de búsqueda", - "HeaderInvitationSent": "Invitación enviada", - "HeaderJellyfinAccountAdded": "Cuenta de Jellyfin añadida", - "HeaderJellyfinAccountRemoved": "Cuenta de Jellyfin eliminada", - "HeaderKeepRecording": "Mantener Grabación", - "HeaderKeepSeries": "Mantener Series", - "HeaderLatestChannelItems": "Últimos elementos de canales", - "HeaderLatestChannelMedia": "Últimos elementos de canales", - "HeaderLatestFrom": "Lo último de {0}", - "HeaderLatestMedia": "Últimos medios", - "HeaderLatestRecordings": "Últimas Grabaciones", - "HeaderLearnMore": "Aprende más", - "HeaderLibraryFolders": "Carpetas de la Biblioteca", - "HeaderLibraryOrder": "Orden de la Biblioteca", - "HeaderMetadataSettings": "Ajustes de metadatos", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "Mi dispositivo", - "HeaderMyDownloads": "Mis Descargas", - "HeaderMyMedia": "Mis Contenidos", - "HeaderMyMediaSmall": "Mis Contenidos (pequeño)", - "HeaderNewRecording": "Nueva grabación", - "HeaderNextEpisodePlayingInValue": "Siguiente episodio empezará en {0}", - "HeaderNextUp": "Siguiendo", - "HeaderNextVideoPlayingInValue": "Siguiente vídeo empezará en {0}", - "HeaderOfflineDownloads": "Medios fuera de línea", - "HeaderOfflineDownloadsDescription": "Descargue los medios a sus dispositivos para un uso sin conexión.", - "HeaderOnNow": "Transmitiendo Ahora", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Reproducir mis contenidos", - "HeaderPlayOn": "Reproducir en", - "HeaderPlaybackError": "Error de reproducción", - "HeaderRecordingOptions": "Ajustes de grabación", - "HeaderRemoteControl": "Control remoto", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Di algo como...", - "HeaderSecondsValue": "{0} segundos", - "HeaderSelectDate": "Seleccionar Fecha", - "HeaderSeriesOptions": "Opciones de Series", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Información del episodio especial", - "HeaderStartNow": "Empezar ahora", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Apariencia de los subtítulos", - "HeaderSubtitleSettings": "Ajustes de subtítulos", - "HeaderSyncRequiresSub": "La descarga requiere de una suscripción activa de Jellyfin Premiere.", - "HeaderTermsOfPurchase": "Términos de compra", - "HeaderTryPlayback": "Reproducción de prueba", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Subir imagen", - "HeaderVideoQuality": "Calidad de Video", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Esperando a la red Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "Dijiste...", - "Help": "Ayuda", - "Hide": "Esconder", - "HideWatchedContentFromLatestMedia": "Esconder medios vistos de los medios más recientes", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "¿Cómo has pagado?", - "IHaveJellyfinPremiere": "Tengo Jellyfin Premiere", - "IPurchasedThisApp": "He comprado esta aplicación", - "Identify": "Identificar", - "Images": "Imágenes", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Instalando {0}", - "InstantMix": "Mix instantáneo", - "InterlacedVideoNotSupported": "Entrelazamiento de video no soportado", - "ItemCount": "ítems {0}", - "Items": "Ítems", - "KeepDownload": "Mantener descarga", - "KeepOnDevice": "Mantener en dispositivo", - "Kids": "Infantil", - "Label3DFormat": "Formato 3D:", - "LabelAirDays": "Días de emisión:", - "LabelAirTime": "Tiempo de emisión:", - "LabelAirsAfterSeason": "Se emite después de la temporada:", - "LabelAirsBeforeEpisode": "Se emite antes del episodio:", - "LabelAirsBeforeSeason": "Se emite antes de la temporada:", - "LabelAlbum": "Álbum", - "LabelAlbumArtists": "Artistas de los álbumes", - "LabelArtists": "Artistas:", - "LabelArtistsHelp": "Separar multiples usando ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Idioma de audio preferido", - "LabelBirthDate": "Fecha de nacimiento:", - "LabelBirthYear": "Año de nacimiento:", - "LabelBitrateMbps": "Tasa de bits (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Canales", - "LabelCollection": "Colección:", - "LabelCommunityRating": "Puntuación de la comunidad", - "LabelContentType": "Tipo de contenido:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "País:", - "LabelCriticRating": "Valoración de la crítica:", - "LabelCustomRating": "Valoración pesonalizada:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Fecha añadido:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Fecha de muerte:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Número de disco:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Modo de visualización:", - "LabelDisplayOrder": "Mostrar orden:", - "LabelDropImageHere": "Soltar imagen aquí, o pulsar para navegar.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} id:", - "LabelEmailAddress": "Dirección de correo", - "LabelEndDate": "Fecha de fin:", - "LabelEpisodeNumber": "Episodio número:", - "LabelFont": "Fuente:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Sección de la pantalla de inicio {0}:", - "LabelImageType": "Tipo de imagen:", - "LabelInternetQuality": "Calidad en internet:", - "LabelItemLimit": "Límite de ítems:", - "LabelKeep:": "Mantener:", - "LabelKeepUpTo": "Mantener hasta:", - "LabelLanguage": "Idioma:", - "LabelLockItemToPreventChanges": "Bloquear este ítem para evitar futuros cambios", - "LabelMaxChromecastBitrate": "Bitrate de reproducción Chromecast", - "LabelMetadataDownloadLanguage": "Idioma preferido visualizado", - "LabelName": "Nombre:", - "LabelNumber": "Número:", - "LabelOriginalAspectRatio": "Relación de aspecto original:", - "LabelOriginalTitle": "Título original", - "LabelOverview": "Resumen:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Clasificación parental:", - "LabelPath": "Ruta:", - "LabelPersonRole": "Rol:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Lugar de nacimiento:", - "LabelPlayDefaultAudioTrack": "Reproducir pista de audio predeterminado, independientemente del idioma", - "LabelPlaylist": "Lista:", - "LabelPreferredSubtitleLanguage": "Idioma de subtítulos preferido", - "LabelProfile": "Perfil:", - "LabelQuality": "Calidad:", - "LabelReasonForTranscoding": "Motivo de transcodificación", - "LabelRecord": "Grabar:", - "LabelRefreshMode": "Modo de refresco:", - "LabelReleaseDate": "Fecha de lanzamiento:", - "LabelRuntimeMinutes": "Tiempo e ejecución (minutos):", - "LabelScreensaver": "Salvapantallas", - "LabelSeasonNumber": "Temporada número:", - "LabelSelectFolderGroups": "Agrupar contenido automáticamente desde las siguientes carpetas en vistas como Películas, Música y Series:", - "LabelSelectFolderGroupsHelp": "Las carpetas sin seleccionar se mostrarán ellas mismas en su propia vista.", - "LabelShortOverview": "Resumen corto:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Clasificar por título:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Empezar cuando sea posible:", - "LabelStatus": "Estado:", - "LabelStopWhenPossible": "Parar cuando sea posible:", - "LabelSubtitlePlaybackMode": "Modo de subtítulo:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Nombre del trabajo de sincronización:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sincronizar en:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Lema:", - "LabelTextBackgroundColor": "Color de fondo del texto:", - "LabelTextColor": "Color del texto:", - "LabelTextSize": "Tamaño del texto:", - "LabelTheme": "Theme:", - "LabelTitle": "Título", - "LabelTrackNumber": "Número de pista:", - "LabelType": "Tipo:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Sitio web:", - "LabelWindowBackgroundColor": "Color de fondo del texto:", - "LabelYear": "Año:", - "Large": "Grande", - "LatestFromLibrary": "Últimas {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Aprende más", - "Like": "Me gusta", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Directo", - "LiveBroadcasts": "Emisiones en vivo", - "LiveTV": "TV en vivo", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "TV en vivo requiere de una suscripción activa de Jellyfin Premiere.", - "Logo": "Logo", - "ManageRecording": "Gestionar grabación", - "MarkPlayed": "Marcar como reproducido", - "MarkUnplayed": "Marcar como no reproducido", - "MarkWatched": "Marcar como visto", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Mediano", - "Menu": "Menú", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Se necesita una suscripción a Jellyfin Premiere para poder crear grabaciones automáticas.", - "MessageAreYouSureDeleteSubtitles": "¿Está seguro que desea eliminar este archivo de subtítulos?", - "MessageConfirmRecordingCancellation": "¿Está seguro que desea cancelar esta grabación?", - "MessageDownloadQueued": "Descarga en cola.", - "MessageFileReadError": "Ha habido un error leyendo el fichero. Por favor inténtalo más tarde.", - "MessageIfYouBlockedVoice": "Si has denegado el acceso a la voz a la aplicación tendrás que reconfigurarlo antes de intentarlo de nuevo.", - "MessageInvitationSentToNewUser": "Se le ha enviado un correo a {0}, invitándolo a que se registre en Jellyfin.", - "MessageInvitationSentToUser": "Se le ha enviado un correo a {0}, invitándolo a que acepte lo que has compartido.", - "MessageItemSaved": "Elemento grabado.", - "MessageItemsAdded": "Items añadidos", - "MessageJellyfinAccontRemoved": "Se ha eliminado la cuenta de Jellyfin para este usuario.", - "MessageJellyfinAccountAdded": "Se ha añadido la cuenta de Jellyfin a este usuario", - "MessageLeaveEmptyToInherit": "Dejar en blanco para heredar la configuración de un elemento principal, o el valor predeterminado global.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No hay servidores disponibles para conectarse. Si te han invitado a unirte a un servidor, asegúrate de aceptar aquí abajo o haciendo clic en el enlace del correo.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "Se ha añadido una cuenta de Jellyfin a este usuario. Se va a enviar un correo al dueño de la cuenta. La invitación necesita confirmarse haciendo clic en el enlace del correo.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "Si tienes una suscripción a Jellyfin Premiere asegúrate de que la has configurado en el Panel de Control de tu servidor Jellyfin en Ayuda -> Jellyfin Premiere.", - "MessageUnlockAppWithPurchaseOrSupporter": "Desbloquea esta característica con una pequeña compra una vez o con una suscripción a Jellyfin Premiere.", - "MessageUnlockAppWithSupporter": "Desbloquea esta característica con una suscripción a Jellyfin Premiere.", - "MessageWeDidntRecognizeCommand": "Lo sentimos, no reconocemos ese comando.", - "MinutesAfter": "minutos después", - "MinutesBefore": "minutos antes", - "Mobile": "Móvil / Tablet", - "Monday": "Lunes", - "More": "Más", - "MoveLeft": "Mover izquierda", - "MoveRight": "Mover derecha", - "Movies": "Peliculas", - "MySubtitles": "Mis Subtitulos", - "Name": "Nombre", - "NewCollection": "Nueva colección", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Ejemplo: Colección de Star Wars", - "NewEpisodes": "Nuevos episodios", - "NewEpisodesOnly": "Solo nuevos episodios", - "News": "Noticias", - "Next": "Siguiente", - "No": "No", - "NoItemsFound": "No se han encontrado ítems", - "NoSubtitleSearchResultsFound": "No se han encontrado resultados.", - "NoSubtitles": "Sin subtítulos", - "NoSubtitlesHelp": "Los subtítulos no se cargarán de forma predeterminada. Tienen que ser activados manualmente durante la reproducción.", - "None": "Nada", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "Un canal", - "OnlyForcedSubtitles": "Sólo subtítulos forzados", - "OnlyForcedSubtitlesHelp": "Sólo se cargarán los subtítulos marcados como forzados.", - "OnlyImageFormats": "Solo formatos de imagen (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Abrir", - "OptionNew": "Nuevo...", - "Original": "Original", - "OriginalAirDateValue": "Fecha de emisión original: {0}", - "Overview": "Sinopsis", - "PackageInstallCancelled": "{0} instalación cancelada.", - "PackageInstallCompleted": "{0} instalación completada.", - "PackageInstallFailed": "{0} instalación fallida.", - "ParentalRating": "Parental Rating", - "People": "Gente", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Situar los canales favoritos al principio", - "Play": "Reproducir", - "PlayAllFromHere": "Reproducir todos desde aquí", - "PlayCount": "Play count", - "PlayFromBeginning": "Iniciar desde el principio", - "PlayNext": "Reproducir siguiente", - "PlayNextEpisodeAutomatically": "Reproducir siguiente episodio automáticamente", - "PlaybackErrorNoCompatibleStream": "No tienes disponible ninguna calidad por ahora. Inténtalo más tarde o contacta con el administrador para más detalles.", - "PlaybackErrorNotAllowed": "No estás autorizado a reproducir este contenido. Contacta con el administrador para más detalles.", - "PlaybackErrorPlaceHolder": "El contenido elegido no se puede reproducir desde este dispositivo.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Reproducido", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Introduzca un nombre o un identificador externo.", - "PleaseRestartServerName": "Por favor, reinicie el Servidor de Jellyfin - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Seleccione al menos dos elementos.", - "Premiere": "Premiere", - "Premieres": "Estrenos", - "Previous": "Anterior", - "Primary": "Principal", - "PrivacyPolicy": "Política de privacidad", - "Producer": "Productor", - "ProductionLocations": "Localizaciones de producción", - "Programs": "Programas", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Calidad", - "QueueAllFromHere": "En cola todos desde aquí", - "Raised": "Raised", - "RecentlyWatched": "Vistos recientemente", - "Record": "Grabar", - "RecordSeries": "Grabar serie", - "RecordingCancelled": "Grabación cancelada.", - "RecordingScheduled": "Grabación programada.", - "Recordings": "Grabaciones", - "RefFramesNotSupported": "Número de cuadros de referencia de video no soportados", - "Refresh": "Refrescar", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Actualizar metadatos", - "RefreshQueued": "Actualiza la cola", - "Reject": "Rechazar", - "ReleaseDate": "Fecha de lanzamiento", - "RemoveDownload": "Eliminar descarga", - "RemoveFromCollection": "Quitar de la colección", - "RemoveFromPlaylist": "Quitar de la lista", - "RemovingFromDevice": "Quitar del dispositivo", - "Repeat": "Repetir", - "RepeatAll": "Repetir todo", - "RepeatEpisodes": "Repetir episodios", - "RepeatMode": "Modo de repetición", - "RepeatOne": "Repetir uno", - "ReplaceAllMetadata": "Reemplazar todos los metadatos", - "ReplaceExistingImages": "Reemplazar imágenes existentes", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Continuar desde {0}", - "Retry": "Reintentar", - "RunAtStartup": "Run at startup", - "Runtime": "Tiempo de Ejecución", - "Saturday": "Sábado", - "Save": "Grabar", - "ScanForNewAndUpdatedFiles": "Buscar archivos nuevos y actualizados", - "Schedule": "Horario", - "Screenshot": "Captura de pantalla", - "Screenshots": "Capturas de pantalla", - "Search": "Buscar", - "SearchForCollectionInternetMetadata": "Buscar en internet ilustraciones y metadatos", - "SearchForMissingMetadata": "Buscar metadatos faltantes", - "SearchForSubtitles": "Búsqueda de Subtítulos", - "SearchResults": "Resultados de la Búsqueda", - "SecondaryAudioNotSupported": "Cambio de pista de audio no soportado", - "SeriesCancelled": "Serie cancelada.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Grabación de series programada.", - "SeriesSettings": "Ajustes de series", - "SeriesYearToPresent": "{0} - Actualidad", - "ServerNameIsRestarting": "El Servidor de Jellyfin - {0} se esta reiniciando.", - "ServerNameIsShuttingDown": "El Servidor de Jellyfin - {0} se esta apagando.", - "ServerUpdateNeeded": "El servidor necesita actualizarse. Para descargar la última versión visita {0}", - "Settings": "Ajustes", - "SettingsSaved": "Configuración guardada.", - "Share": "Compartir", - "ShowIndicatorsFor": "Mostrar indicaciones para:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Series", - "Shuffle": "Mezclar", - "SkipEpisodesAlreadyInMyLibrary": "No grabar episodios que ya están en mi libreria", - "SkipEpisodesAlreadyInMyLibraryHelp": "Los episodios serán comparados usando el número de temporada y de episodio, cuando estén disponibles.", - "Small": "Pequeño", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Listo", - "SmartSubtitlesHelp": "Los subtítulos que coincidan con el idioma preferido se activarán cuando el audio esté en otro idioma.", - "Songs": "Canciones", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Ordenar canales por:", - "SortName": "Ordenar por nombre", - "Sports": "Deportes", - "StatsForNerds": "Estadísticas para Frikis", - "StopRecording": "Parar grabación", - "Studios": "Estudios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Formato de subtítulos no soportado", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtítulos", - "Suggestions": "Sugerencias", - "Sunday": "Domingo", - "Sync": "Sincronizar", - "SyncJobItemStatusCancelled": "Cancelado", - "SyncJobItemStatusConverting": "Convirtiendo", - "SyncJobItemStatusFailed": "Fallido", - "SyncJobItemStatusQueued": "En cola", - "SyncJobItemStatusReadyToTransfer": "Listo para transferir", - "SyncJobItemStatusRemovedFromDevice": "Quitado del dispositivo", - "SyncJobItemStatusSynced": "Descargado", - "SyncJobItemStatusSyncedMarkForRemoval": "Quitar del dispositivo", - "SyncJobItemStatusTransferring": "Transfiriendo", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Etiquetas", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Términos de uso", - "ThankYouForTryingEnjoyOneMinute": "Disfruta de un minuto de reproducción. Gracias por probar Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "Estas opciones afectan a los subtítulos en este dispositivo", - "Thumb": "Miniatura", - "Thursday": "Jueves", - "TrackCount": "{0} pistas", - "Trailer": "Tráiler", - "Trailers": "Trailers", - "Transcoding": "Transcodificación", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Martes", - "Uniform": "Uniform", - "UnlockGuide": "Guía de desbloqueo", - "Unplayed": "Unplayed", - "Unrated": "Sin clasificar", - "UntilIDelete": "Hasta que lo elimine", - "UntilSpaceNeeded": "Hasta que necesite espacio", - "Up": "Arriba", - "Upload": "Subir", - "ValueAlbumCount": "{0} álbumes", - "ValueDiscNumber": "Disco {0}", - "ValueEpisodeCount": "{0} episodios", - "ValueGameCount": "{0} juegos", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} películas", - "ValueMusicVideoCount": "{0} vídeos musicales", - "ValueOneAlbum": "1 álbum", - "ValueOneEpisode": "1 episodio", - "ValueOneGame": "1 juego", - "ValueOneItem": "1 elemento", - "ValueOneMovie": "1 película", - "ValueOneMusicVideo": "1 vídeo musical", - "ValueOneSeries": "1 serie", - "ValueOneSong": "1 canción", - "ValueSeconds": "{0} segundos", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} canciones", - "ValueSpecialEpisodeName": "Especial - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Profundidad de bits de video no soportados", - "VideoCodecNotSupported": "Codec de video no soportado", - "VideoFramerateNotSupported": "Cuadros por segundo de video no soportados", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Perfil de video no soportado", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Resolución de video no soportada", - "ViewAlbum": "Ver album", - "ViewArtist": "Ver artista", - "VoiceInput": "Entrada de voz", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Visto", - "Wednesday": "Miércoles", - "WifiRequiredToDownload": "Una red Wifi es necesaria para continuar la descarga.", - "Writer": "Escritor", - "Yes": "Si" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "Desbloquea esta caracter\u00edstica con una peque\u00f1a compra una vez o con una suscripci\u00f3n a Emby Premiere.", + "MessageUnlockAppWithSupporter": "Desbloquea esta caracter\u00edstica con una suscripci\u00f3n a Emby Premiere.", + "MessageToValidateSupporter": "Si tienes una suscripci\u00f3n a Emby Premiere aseg\u00farate de que la has configurado en el Panel de Control de tu servidor Emby en Ayuda -> Emby Premiere.", + "ValueSpecialEpisodeName": "Especial - {0}", + "Share": "Compartir", + "Add": "A\u00f1adir", + "ServerUpdateNeeded": "El servidor necesita actualizarse. Para descargar la \u00faltima versi\u00f3n visita {0}", + "LiveTvRequiresUnlock": "TV en vivo requiere de una suscripci\u00f3n activa de Emby Premiere.", + "AttributeNew": "Nuevo", + "Premiere": "Premiere", + "Live": "Directo", + "Repeat": "Repetir", + "TrackCount": "{0} pistas", + "ItemCount": "\u00edtems {0}", + "OriginalAirDateValue": "Fecha de emisi\u00f3n original: {0}", + "EndsAtValue": "Termina a las {0}", + "HeaderSelectDate": "Seleccionar Fecha", + "Watched": "Visto", + "AirDate": "Air date", + "Played": "Reproducido", + "ButtonOk": "Ok", + "ButtonCancel": "Cancelar", + "AccessRestrictedTryAgainLater": "El acceso est\u00e1 restringido actualmente. Por favor int\u00e9ntalo m\u00e1s tarde.", + "ButtonGotIt": "Lo tengo", + "ButtonRestart": "Reiniciar", + "RecordingCancelled": "Grabaci\u00f3n cancelada.", + "SeriesCancelled": "Serie cancelada.", + "RecordingScheduled": "Grabaci\u00f3n programada.", + "SeriesRecordingScheduled": "Grabaci\u00f3n de series programada.", + "HeaderNewRecording": "Nueva grabaci\u00f3n", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Domingo", + "Monday": "Lunes", + "Tuesday": "Martes", + "Wednesday": "Mi\u00e9rcoles", + "Thursday": "Jueves", + "Friday": "Viernes", + "Saturday": "S\u00e1bado", + "Days": "D\u00edas", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Grabar serie", + "HeaderCinemaMode": "Modo cine", + "HeaderCloudSync": "Sincronizaci\u00f3n en la nube", + "Downloads": "Descargas", + "HeaderMyDownloads": "Mis Descargas", + "HeaderOfflineDownloads": "Medios fuera de l\u00ednea", + "HeaderOfflineDownloadsDescription": "Descargue los medios a sus dispositivos para un uso sin conexi\u00f3n.", + "CloudSyncFeatureDescription": "Sincroniza tus medios en la nube para una copia de seguridad, archivado y conversi\u00f3n f\u00e1cil.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "CinemaModeFeatureDescription": "El Modo Cine te da la verdadera experiencia de cine con tr\u00e1ilers e intros personalizadas antes de la funci\u00f3n principal.", + "HeaderFreeApps": "Apps de Emby gratuitas", + "FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.", + "HeaderBecomeProjectSupporter": "Consigue Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Se necesita una suscripci\u00f3n a Emby Premiere para poder crear grabaciones autom\u00e1ticas.", + "LabelEmailAddress": "Direcci\u00f3n de correo", + "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": "Esta caracter\u00edstica necesita una suscripci\u00f3n a Emby Premiere.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Grabar", + "Save": "Grabar", + "Edit": "Editar", + "Download": "Descargar", + "Downloaded": "Descargado", + "Downloading": "Descargando", + "Advanced": "Avanzado", + "Delete": "Borrar", + "HeaderDeleteItem": "Borrar elemento", + "ConfirmDeleteItem": "Al borrar este \u00edtem se borrar\u00e1 del sistema de archivos y de la biblioteca. \u00bfQuieres continuar?", + "Refresh": "Refrescar", + "RefreshQueued": "Actualiza la cola", + "AddToCollection": "A\u00f1adir a la colecci\u00f3n", + "HeaderAddToCollection": "Agregar a la colecci\u00f3n", + "NewCollection": "Nueva colecci\u00f3n", + "LabelCollection": "Colecci\u00f3n:", + "Help": "Ayuda", + "LabelDisplayMode": "Modo de visualizaci\u00f3n:", + "Desktop": "Escritorio", + "Mobile": "M\u00f3vil \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Seleccione el tipo de pantalla que est\u00e1 ejecutando Emby.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Buscar en internet ilustraciones y metadatos", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Habilitar temas videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Salvapantallas", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Nombre:", + "NewCollectionNameExample": "Ejemplo: Colecci\u00f3n de Star Wars", + "MessageItemsAdded": "Items a\u00f1adidos", + "OptionNew": "Nuevo...", + "LabelPlaylist": "Lista:", + "AddToPlaylist": "A\u00f1adir a la lista de reproducci\u00f3n", + "HeaderAddToPlaylist": "A\u00f1adir a la lista", + "Subtitles": "Subt\u00edtulos", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "B\u00fasqueda de Subt\u00edtulos", + "LabelLanguage": "Idioma:", + "Search": "Buscar", + "NoSubtitleSearchResultsFound": "No se han encontrado resultados.", + "File": "Archivo", + "MessageAreYouSureDeleteSubtitles": "\u00bfEst\u00e1 seguro que desea eliminar este archivo de subt\u00edtulos?", + "ConfirmDeletion": "Confirmar borrado", + "MySubtitles": "Mis Subtitulos", + "MessageDownloadQueued": "Descarga en cola.", + "EditSubtitles": "Editar subt\u00edtulos", + "UnlockGuide": "Gu\u00eda de desbloqueo", + "RefreshMetadata": "Actualizar metadatos", + "ReplaceExistingImages": "Reemplazar im\u00e1genes existentes", + "ReplaceAllMetadata": "Reemplazar todos los metadatos", + "SearchForMissingMetadata": "Buscar metadatos faltantes", + "LabelRefreshMode": "Modo de refresco:", + "NoItemsFound": "No se han encontrado \u00edtems", + "HeaderSaySomethingLike": "Di algo como...", + "ButtonTryAgain": "Int\u00e9ntalo de nuevo", + "HeaderYouSaid": "Dijiste...", + "MessageWeDidntRecognizeCommand": "Lo sentimos, no reconocemos ese comando.", + "MessageIfYouBlockedVoice": "Si has denegado el acceso a la voz a la aplicaci\u00f3n tendr\u00e1s que reconfigurarlo antes de intentarlo de nuevo.", + "ValueDiscNumber": "Disco {0}", + "Unrated": "Sin clasificar", + "Favorite": "Favorito", + "Like": "Me gusta", + "Dislike": "No me gusta", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Abrir", + "Play": "Reproducir", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Mezclar", + "Identify": "Identificar", + "EditImages": "Editar im\u00e1genes", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sincronizar", + "InstantMix": "Mix instant\u00e1neo", + "ViewAlbum": "Ver album", + "ViewArtist": "Ver artista", + "QueueAllFromHere": "En cola todos desde aqu\u00ed", + "PlayAllFromHere": "Reproducir todos desde aqu\u00ed", + "PlayFromBeginning": "Iniciar desde el principio", + "ResumeAt": "Continuar desde {0}", + "RemoveFromPlaylist": "Quitar de la lista", + "RemoveFromCollection": "Quitar de la colecci\u00f3n", + "Sort": "Sort", + "Trailer": "Tr\u00e1iler", + "MarkPlayed": "Marcar como reproducido", + "MarkUnplayed": "Marcar como no reproducido", + "GroupVersions": "Agrupar versiones", + "PleaseSelectTwoItems": "Seleccione al menos dos elementos.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirmar la cancelaci\u00f3n de la grabaci\u00f3n", + "MessageConfirmRecordingCancellation": "\u00bfEst\u00e1 seguro que desea cancelar esta grabaci\u00f3n?", + "Error": "Error", + "VoiceInput": "Entrada de voz", + "LabelContentType": "Tipo de contenido:", + "LabelPath": "Ruta:", + "Playlists": "Playlists", + "LabelTitle": "T\u00edtulo", + "LabelOriginalTitle": "T\u00edtulo original", + "LabelSortTitle": "Clasificar por t\u00edtulo:", + "LabelDateAdded": "Fecha a\u00f1adido:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configura como la fecha a\u00f1adida se determina en el Panel de Control del servidor Emby en los ajustes de la biblioteca.", + "LabelStatus": "Estado:", + "LabelArtists": "Artistas:", + "LabelArtistsHelp": "Separar multiples usando ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Artistas de los \u00e1lbumes", + "LabelAlbum": "\u00c1lbum", + "Artists": "Artistas", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Puntuaci\u00f3n de la comunidad", + "LabelCriticRating": "Valoraci\u00f3n de la cr\u00edtica:", + "CriticRating": "Critic rating", + "LabelWebsite": "Sitio web:", + "LabelTagline": "Lema:", + "LabelOverview": "Resumen:", + "LabelShortOverview": "Resumen corto:", + "LabelReleaseDate": "Fecha de lanzamiento:", + "LabelYear": "A\u00f1o:", + "LabelPlaceOfBirth": "Lugar de nacimiento:", + "Aired": "Aired", + "LabelAirDays": "D\u00edas de emisi\u00f3n:", + "LabelAirTime": "Tiempo de emisi\u00f3n:", + "LabelRuntimeMinutes": "Tiempo e ejecuci\u00f3n (minutos):", + "LabelParentalRating": "Clasificaci\u00f3n parental:", + "LabelCustomRating": "Valoraci\u00f3n pesonalizada:", + "LabelOriginalAspectRatio": "Relaci\u00f3n de aspecto original:", + "Label3DFormat": "Formato 3D:", + "FormatValue": "Formato: {0}", + "DownloadsValue": "Descargas: {0}", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Activar reproductores externos", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Informaci\u00f3n del episodio especial", + "LabelAirsBeforeSeason": "Se emite antes de la temporada:", + "LabelAirsAfterSeason": "Se emite despu\u00e9s de la temporada:", + "LabelAirsBeforeEpisode": "Se emite antes del episodio:", + "HeaderExternalIds": "Ids externos:", + "HeaderDisplaySettings": "Opciones de pantalla", + "LabelDisplayOrder": "Mostrar orden:", + "Display": "Display", + "Countries": "Pa\u00edses", + "Genres": "G\u00e9neros", + "Studios": "Estudios", + "Tags": "Etiquetas", + "HeaderMetadataSettings": "Ajustes de metadatos", + "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.", + "LabelCountry": "Pa\u00eds:", + "LabelDynamicExternalId": "{0} id:", + "LabelBirthYear": "A\u00f1o de nacimiento:", + "LabelBirthDate": "Fecha de nacimiento:", + "LabelDeathDate": "Fecha de muerte:", + "LabelEndDate": "Fecha de fin:", + "LabelSeasonNumber": "Temporada n\u00famero:", + "LabelEpisodeNumber": "Episodio n\u00famero:", + "LabelTrackNumber": "N\u00famero de pista:", + "LabelNumber": "N\u00famero:", + "LabelDiscNumber": "N\u00famero de disco:", + "LabelParentNumber": "Parent number:", + "SortName": "Ordenar por nombre", + "ReleaseDate": "Fecha de lanzamiento", + "Continuing": "Continuando", + "Ended": "Finalizado", + "HeaderEnabledFields": "Campos activados", + "HeaderEnabledFieldsHelp": "Desmarca un campo para bloquearlo y evitar que se cambie su contenido.", + "Backdrops": "Im\u00e1genes de fondo", + "Images": "Im\u00e1genes", + "Runtime": "Tiempo de Ejecuci\u00f3n", + "ProductionLocations": "Localizaciones de producci\u00f3n", + "BirthLocation": "Lugar de nacimiento", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Nombre", + "Overview": "Sinopsis", + "LabelType": "Tipo:", + "LabelPersonRole": "Rol:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Compositor", + "Director": "Director", + "GuestStar": "Estrella invitada", + "Producer": "Productor", + "Writer": "Escritor", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Instalando {0}", + "PackageInstallCompleted": "{0} instalaci\u00f3n completada.", + "PackageInstallFailed": "{0} instalaci\u00f3n fallida.", + "PackageInstallCancelled": "{0} instalaci\u00f3n cancelada.", + "SeriesYearToPresent": "{0} - Actualidad", + "ValueOneItem": "1 elemento", + "ValueOneSong": "1 canci\u00f3n", + "ValueSongCount": "{0} canciones", + "ValueOneMovie": "1 pel\u00edcula", + "ValueMovieCount": "{0} pel\u00edculas", + "ValueOneSeries": "1 serie", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episodio", + "ValueEpisodeCount": "{0} episodios", + "ValueOneGame": "1 juego", + "ValueGameCount": "{0} juegos", + "ValueOneAlbum": "1 \u00e1lbum", + "ValueAlbumCount": "{0} \u00e1lbumes", + "ValueOneMusicVideo": "1 v\u00eddeo musical", + "ValueMusicVideoCount": "{0} v\u00eddeos musicales", + "ValueMinutes": "{0} min", + "Albums": "\u00c1lbumes", + "Songs": "Canciones", + "Books": "Libros", + "HeaderAudioBooks": "Audiolibros", + "HeaderIdentifyItemHelp": "Asigna uno o m\u00e1s criterios de b\u00fasqueda. Quita criterios para aumentar el n\u00famero de resultados de b\u00fasqueda", + "PleaseEnterNameOrId": "Introduzca un nombre o un identificador externo.", + "MessageItemSaved": "Elemento grabado.", + "SearchResults": "Resultados de la B\u00fasqueda", + "ServerNameIsRestarting": "El Servidor de Emby - {0} se esta reiniciando.", + "ServerNameIsShuttingDown": "El Servidor de Emby - {0} se esta apagando.", + "HeaderDeleteItems": "Borrar \u00edtems", + "ConfirmDeleteItems": "Al borrar este \u00edtem se borrar\u00e1 del sistema de archivos y de la biblioteca. \u00bfQuieres continuar?", + "PleaseRestartServerName": "Por favor, reinicie el Servidor de Emby - {0}.", + "LabelSyncJobName": "Nombre del trabajo de sincronizaci\u00f3n:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Calidad:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Descargando", + "HeaderSyncRequiresSub": "La descarga requiere de una suscripci\u00f3n activa de Emby Premiere.", + "LearnMore": "Aprende m\u00e1s", + "LabelProfile": "Perfil:", + "LabelBitrateMbps": "Tasa de bits (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Descargar autom\u00e1ticamente contenido nuevo", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "L\u00edmite de \u00edtems:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Capturas de pantalla", + "MoveRight": "Mover derecha", + "MoveLeft": "Mover izquierda", + "ConfirmDeleteImage": "Borrar imagen", + "HeaderEditImages": "Editar Im\u00e1genes", + "Settings": "Ajustes", + "ShowIndicatorsFor": "Mostrar indicaciones para:", + "NewEpisodes": "Nuevos episodios", + "Episodes": "Episodios", + "HDPrograms": "Programas en HD", + "Programs": "Programas", + "LiveBroadcasts": "Emisiones en vivo", + "Premieres": "Estrenos", + "RepeatEpisodes": "Repetir episodios", + "DvrSubscriptionRequired": "Emby DVR requires an active Emby Premiere subscription.", + "HeaderCancelRecording": "Cancelar Grabaci\u00f3n", + "CancelRecording": "Cancelar grabaci\u00f3n", + "HeaderKeepRecording": "Mantener Grabaci\u00f3n", + "HeaderCancelSeries": "Cancelar Series", + "HeaderKeepSeries": "Mantener Series", + "HeaderLearnMore": "Aprende m\u00e1s", + "DeleteMedia": "Eliminar medios", + "SeriesSettings": "Ajustes de series", + "HeaderRecordingOptions": "Ajustes de grabaci\u00f3n", + "CancelSeries": "Cancelar series", + "DoNotRecord": "No grabar", + "HeaderSeriesOptions": "Opciones de Series", + "LabelChannels": "Canales", + "ChannelNameOnly": "Canal {0} solo", + "Anytime": "Anytime", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "Todo", + "AllChannels": "Todos los canales", + "LabelRecord": "Grabar:", + "NewEpisodesOnly": "Solo nuevos episodios", + "AllEpisodes": "Todos los episodios", + "LabelStartWhenPossible": "Empezar cuando sea posible:", + "LabelStopWhenPossible": "Parar cuando sea posible:", + "MinutesBefore": "minutos antes", + "MinutesAfter": "minutos despu\u00e9s", + "SkipEpisodesAlreadyInMyLibrary": "No grabar episodios que ya est\u00e1n en mi libreria", + "SkipEpisodesAlreadyInMyLibraryHelp": "Los episodios ser\u00e1n comparados usando el n\u00famero de temporada y de episodio, cuando est\u00e9n disponibles.", + "LabelKeepUpTo": "Mantener hasta:", + "AsManyAsPossible": "Tantos como sea posible", + "DefaultErrorMessage": "Ha habido un error procesando la solicitud. Por favor int\u00e9ntalo m\u00e1s tarde.", + "LabelKeep:": "Mantener:", + "UntilIDelete": "Hasta que lo elimine", + "UntilSpaceNeeded": "Hasta que necesite espacio", + "Categories": "Categor\u00edas", + "Sports": "Deportes", + "News": "Noticias", + "Movies": "Peliculas", + "Kids": "Infantil", + "EnableColorCodedBackgrounds": "Enable color coded backgrounds", + "SortChannelsBy": "Ordenar canales por:", + "RecentlyWatched": "Vistos recientemente", + "ChannelNumber": "N\u00famero de canal", + "HeaderBenefitsEmbyPremiere": "Beneficios de Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "Disfruta de un minuto de reproducci\u00f3n. Gracias por probar Emby.", + "HeaderTryPlayback": "Reproducci\u00f3n de prueba", + "HowDidYouPay": "\u00bfC\u00f3mo has pagado?", + "IHaveEmbyPremiere": "Tengo Emby Premiere", + "IPurchasedThisApp": "He comprado esta aplicaci\u00f3n", + "ButtonRestorePreviousPurchase": "Recuperar compra", + "ButtonUnlockWithPurchase": "Desbloquear con una compra", + "ButtonUnlockPrice": "Desbloquear {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere mensual {0}", + "HeaderAlreadyPaid": "\u00bfYa has pagado?", + "ButtonPlayOneMinute": "Reproducir un minuto", + "PlaceFavoriteChannelsAtBeginning": "Situar los canales favoritos al principio", + "HeaderUnlockFeature": "Unlock Feature", + "MessageDidYouKnowCinemaMode": "\u00bfSab\u00edas que con Emby Premiere puedes mejorar tu experiencia con caracter\u00edsticas como el Modo Cine?", + "MessageDidYouKnowCinemaMode2": "El Modo Cine te da la verdadera experiencia de cine con tr\u00e1ilers e intros personalizadas antes de la funci\u00f3n principal.", + "HeaderPlayMyMedia": "Reproducir mis contenidos", + "HeaderDiscoverEmbyPremiere": "Descubre Emby Premiere", + "Items": "\u00cdtems", + "OneChannel": "Un canal", + "ConfirmRemoveDownload": "\u00bfQuieres eliminar la descarga?", + "RemoveDownload": "Eliminar descarga", + "KeepDownload": "Mantener descarga", + "AddedOnValue": "A\u00f1adido {0}", + "RemovingFromDevice": "Quitar del dispositivo", + "KeepOnDevice": "Mantener en dispositivo", + "CancelDownload": "Cancelar descarga", + "SyncJobItemStatusReadyToTransfer": "Listo para transferir", + "SyncJobItemStatusSyncedMarkForRemoval": "Quitar del dispositivo", + "SyncJobItemStatusQueued": "En cola", + "SyncJobItemStatusConverting": "Convirtiendo", + "SyncJobItemStatusTransferring": "Transfiriendo", + "SyncJobItemStatusSynced": "Descargado", + "SyncJobItemStatusFailed": "Fallido", + "SyncJobItemStatusRemovedFromDevice": "Quitado del dispositivo", + "SyncJobItemStatusCancelled": "Cancelado", + "Retry": "Reintentar", + "HeaderMyDevice": "Mi dispositivo", + "Continue": "Continuar", + "ContinueInSecondsValue": "Continuar en {0} segundos", + "HeaderRemoteControl": "Control remoto", + "Disconnect": "Desconectar", + "EnableDisplayMirroring": "Activar mirroring de la pantalla", + "HeaderPlayOn": "Reproducir en", + "Quality": "Calidad", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Relaci\u00f3n de aspecto", + "Original": "Original", + "Fill": "Llenar", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No hay servidores disponibles para conectarse. Si te han invitado a unirte a un servidor, aseg\u00farate de aceptar aqu\u00ed abajo o haciendo clic en el enlace del correo.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Aceptar", + "Reject": "Rechazar", + "Connect": "Conectar", + "HeaderMyMedia": "Mis Contenidos", + "HeaderMyMediaSmall": "Mis Contenidos (peque\u00f1o)", + "LatestFromLibrary": "\u00daltimas {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "\u00daltimos elementos de canales", + "HeaderContinueWatching": "Continuar viendo", + "HeaderContinueListening": "Continuar escuchando", + "HeaderActiveRecordings": "Grabaciones activas", + "HeaderLatestRecordings": "\u00daltimas Grabaciones", + "LabelSyncTo": "Sincronizar en:", + "LabelConvertTo": "Convert to:", + "Next": "Siguiente", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "Todos los idiomas", + "Previous": "Anterior", + "HeaderNextUp": "Siguiendo", + "HeaderLatestFrom": "Lo \u00faltimo de {0}", + "LabelHomeScreenSectionValue": "Secci\u00f3n de la pantalla de inicio {0}:", + "SettingsSaved": "Configuraci\u00f3n guardada.", + "None": "Nada", + "More": "M\u00e1s", + "Up": "Arriba", + "Down": "Abajo", + "Home": "Home", + "Favorites": "Favoritos", + "HeaderHomeScreen": "Pantalla de inicio", + "HeaderLatestChannelItems": "\u00daltimos elementos de canales", + "HeaderLibraryOrder": "Orden de la Biblioteca", + "HideWatchedContentFromLatestMedia": "Esconder medios vistos de los medios m\u00e1s recientes", + "HeaderOnNow": "Transmitiendo Ahora", + "HeaderPlaybackError": "Error de reproducci\u00f3n", + "PlaybackErrorNotAllowed": "No est\u00e1s autorizado a reproducir este contenido. Contacta con el administrador para m\u00e1s detalles.", + "PlaybackErrorNoCompatibleStream": "No tienes disponible ninguna calidad por ahora. Int\u00e9ntalo m\u00e1s tarde o contacta con el administrador para m\u00e1s detalles.", + "PlaybackErrorPlaceHolder": "El contenido elegido no se puede reproducir desde este dispositivo.", + "Guide": "Gu\u00eda", + "Suggestions": "Sugerencias", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Colecciones", + "LabelSelectFolderGroups": "Agrupar contenido autom\u00e1ticamente desde las siguientes carpetas en vistas como Pel\u00edculas, M\u00fasica y Series:", + "LabelSelectFolderGroupsHelp": "Las carpetas sin seleccionar se mostrar\u00e1n ellas mismas en su propia vista.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Series", + "HeaderLibraryFolders": "Carpetas de la Biblioteca", + "HeaderTermsOfPurchase": "T\u00e9rminos de compra", + "PrivacyPolicy": "Pol\u00edtica de privacidad", + "TermsOfUse": "T\u00e9rminos de uso", + "RepeatMode": "Modo de repetici\u00f3n", + "RepeatOne": "Repetir uno", + "RepeatAll": "Repetir todo", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "\u00bfQuieres cerrar Emby en el dispositivo?", + "Yes": "Si", + "No": "No", + "LiveTV": "TV en vivo", + "Schedule": "Horario", + "Recordings": "Grabaciones", + "MarkWatched": "Marcar como visto", + "ScanForNewAndUpdatedFiles": "Buscar archivos nuevos y actualizados", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Estad\u00edsticas para Frikis", + "LabelReasonForTranscoding": "Motivo de transcodificaci\u00f3n", + "DirectPlaying": "Reproducci\u00f3n directa", + "DirectStreaming": "Streaming directo", + "Transcoding": "Transcodificaci\u00f3n", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Codec de video no soportado", + "AudioCodecNotSupported": "Codec de audio no soportado", + "SubtitleCodecNotSupported": "Formato de subt\u00edtulos no soportado", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Contenedor no soportado", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Canales de audio no soportados", + "VideoResolutionNotSupported": "Resoluci\u00f3n de video no soportada", + "AudioProfileNotSupported": "Perfil de audio no soportado", + "AudioSampleRateNotSupported": "Frecuencia de muestreo de audio no soportada", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Entrelazamiento de video no soportado", + "SecondaryAudioNotSupported": "Cambio de pista de audio no soportado", + "ErrorRemovingEmbyConnectAccount": "Ha habido un error quitando la cuenta de Emby Connect. Por favor aseg\u00farate de que tienes una conexi\u00f3n a internet activa e int\u00e9ntalo otra vez.", + "HeaderEmbyAccountRemoved": "Cuenta de Emby eliminada", + "MessageEmbyAccontRemoved": "Se ha eliminado la cuenta de Emby para este usuario.", + "HeaderInvitationSent": "Invitaci\u00f3n enviada", + "MessageInvitationSentToUser": "Se le ha enviado un correo a {0}, invit\u00e1ndolo a que acepte lo que has compartido.", + "MessageInvitationSentToNewUser": "Se le ha enviado un correo a {0}, invit\u00e1ndolo a que se registre en Emby.", + "GuestUserNotFound": "Usuario no encontrado. Aseg\u00farese de que el nombre es correcto y vuelva a intentarlo o intente ingresar su direcci\u00f3n de correo electr\u00f3nico.", + "ErrorReachingEmbyConnect": "Ha habido un error accediendo al servidor Emby Connect. Por favor, aseg\u00farate de que tienes conexi\u00f3n a internet e int\u00e9ntalo de nuevo.", + "ErrorAddingEmbyConnectAccount1": "Ha habido un error a\u00f1adiendo la cuenta de Emby Connect. \u00bfTe has creado una cuenta de Emby primero? Reg\u00edstrate en {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "Se ha producido un error al agregar la cuenta Emby Connect. \u00bfHa creado su invitado una cuenta de Emby? Pueden registrarse en {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "Se ha a\u00f1adido la cuenta de Emby a este usuario", + "MessagePendingEmbyAccountAdded": "Se ha a\u00f1adido una cuenta de Emby a este usuario. Se va a enviar un correo al due\u00f1o de la cuenta. La invitaci\u00f3n necesita confirmarse haciendo clic en el enlace del correo.", + "HeaderEmbyAccountAdded": "Cuenta de Emby a\u00f1adida", + "LabelSubtitlePlaybackMode": "Modo de subt\u00edtulo:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "Sin subt\u00edtulos", + "Default": "Por defecto", + "Absolute": "Absolute", + "Smart": "Listo", + "Small": "Peque\u00f1o", + "Smaller": "Smaller", + "Medium": "Mediano", + "Large": "Grande", + "ExtraLarge": "Extragrande", + "OnlyForcedSubtitles": "S\u00f3lo subt\u00edtulos forzados", + "AlwaysPlaySubtitles": "Mostrar siempre subt\u00edtulos", + "DefaultSubtitlesHelp": "Los subt\u00edtulos se activan en funci\u00f3n de los ajustes por defecto y etiquetas en los metadatos integrados. Los ajustes de idioma se tienen en cuenta cuando hay varias opciones disponibles.", + "SmartSubtitlesHelp": "Los subt\u00edtulos que coincidan con el idioma preferido se activar\u00e1n cuando el audio est\u00e9 en otro idioma.", + "HeaderSubtitleSettings": "Ajustes de subt\u00edtulos", + "HeaderSubtitleAppearance": "Apariencia de los subt\u00edtulos", + "OnlyForcedSubtitlesHelp": "S\u00f3lo se cargar\u00e1n los subt\u00edtulos marcados como forzados.", + "AlwaysPlaySubtitlesHelp": "Los subt\u00edtulos que concuerden con la preferencia de idioma se cargar\u00e1n independientemente del idioma de audio.", + "NoSubtitlesHelp": "Los subt\u00edtulos no se cargar\u00e1n de forma predeterminada. Tienen que ser activados manualmente durante la reproducci\u00f3n.", + "LabelPreferredSubtitleLanguage": "Idioma de subt\u00edtulos preferido", + "LabelTextSize": "Tama\u00f1o del texto:", + "TheseSettingsAffectSubtitlesOnThisDevice": "Estas opciones afectan a los subt\u00edtulos en este dispositivo", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Color de fondo del texto:", + "LabelWindowBackgroundColor": "Color de fondo del texto:", + "LabelFont": "Fuente:", + "LabelTextColor": "Color del texto:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Solo formatos de imagen (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "Todos los formatos complejos (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Esperando a la red Wifi", + "WifiRequiredToDownload": "Una red Wifi es necesaria para continuar la descarga.", + "HeaderDownloadSettings": "Ajustes de descargas", + "Hide": "Esconder", + "HeaderStartNow": "Empezar ahora", + "HeaderNextVideoPlayingInValue": "Siguiente v\u00eddeo empezar\u00e1 en {0}", + "HeaderNextEpisodePlayingInValue": "Siguiente episodio empezar\u00e1 en {0}", + "HeaderSecondsValue": "{0} segundos", + "AudioBitDepthNotSupported": "Profundidad de bits de audio no soportada", + "VideoProfileNotSupported": "Perfil de video no soportado", + "VideoFramerateNotSupported": "Cuadros por segundo de video no soportados", + "VideoBitDepthNotSupported": "Profundidad de bits de video no soportados", + "RefFramesNotSupported": "N\u00famero de cuadros de referencia de video no soportados", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Parar grabaci\u00f3n", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Gestionar grabaci\u00f3n", + "LabelDropImageHere": "Soltar imagen aqu\u00ed, o pulsar para navegar.", + "MessageFileReadError": "Ha habido un error leyendo el fichero. Por favor int\u00e9ntalo m\u00e1s tarde.", + "Browse": "Navegar", + "HeaderUploadImage": "Subir imagen", + "HeaderAddUpdateImage": "A\u00f1adir\/Actualizar imagen", + "LabelImageType": "Tipo de imagen:", + "Upload": "Subir", + "Primary": "Principal", + "Art": "Arte", + "Backdrop": "Imagen de fondo", + "Banner": "Banner", + "Box": "Caja", + "BoxRear": "Caja (trasera)", + "Disc": "Disco", + "Logo": "Logo", + "Menu": "Men\u00fa", + "Screenshot": "Captura de pantalla", + "Thumb": "Miniatura", + "ValueSeconds": "{0} segundos", + "HeaderAudioSettings": "Ajustes de audio", + "LabelAudioLanguagePreference": "Idioma de audio preferido", + "LabelPlayDefaultAudioTrack": "Reproducir pista de audio predeterminado, independientemente del idioma", + "HeaderVideoQuality": "Calidad de Video", + "CinemaModeConfigurationHelp": "El modo cine proporciona la experiencia del cine directamente en su sala de estar con la capacidad de reproducir trailers e introducciones personalizadas antes de la funci\u00f3n principal.", + "EnableNextVideoInfoOverlay": "Activar la informaci\u00f3n del siguiente video durante la reproducci\u00f3n", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Reproducir siguiente episodio autom\u00e1ticamente", + "LabelMaxChromecastBitrate": "Bitrate de reproducci\u00f3n Chromecast", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Activar modo cine", + "LabelInternetQuality": "Calidad en internet:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "\u00daltimos medios", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Reproducir siguiente", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/fi.json b/src/bower_components/emby-webcomponents/strings/fi.json index c6329252ec..0dcd5d918c 100644 --- a/src/bower_components/emby-webcomponents/strings/fi.json +++ b/src/bower_components/emby-webcomponents/strings/fi.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Lopeta", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friday", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Maa:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Kieli:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Monday", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Saturday", - "Save": "Tallenna", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Sunday", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Thursday", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tuesday", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Wednesday", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Lopeta", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Tallenna", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Kieli:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Maa:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/fr-ca.json b/src/bower_components/emby-webcomponents/strings/fr-ca.json index 4002a0c0f9..59cfe9b891 100644 --- a/src/bower_components/emby-webcomponents/strings/fr-ca.json +++ b/src/bower_components/emby-webcomponents/strings/fr-ca.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Ajouter", - "AddToCollection": "Ajouter à la collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Ajouter à la liste de lecture", - "AddedOnValue": "Added {0}", - "Advanced": "Avancé", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "Nouveau", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Annuler", - "ButtonGotIt": "J'ai compris", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Redémarrer", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Le Mode Cinéma vous donne la véritable expérience cinématographique avec des bandes annonces et des intros personnalisés avant le film.", - "CloudSyncFeatureDescription": "Synchronisez vos médias avec le Cloud pour faciliter la sauvegarde, l'archivage et la conversion.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "La suppression de cet élément le supprimera à la fois du système de fichiers et de votre médiathèque. Êtes-vous sûr de vouloir continuer?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Jours", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Supprimer", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Se déconnecter", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Télécharger", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Modifier", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Activer l'affichage mirroir", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Se termine à {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "Cette fonctionnalité nécessite un abonnement Jellyfin Première actif.", - "Features": "Features", - "File": "Fichier", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Profitez de l'accès gratuit aux applications Jellyfin pour vos appareils.", - "Friday": "Vendredi", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Ajouter à la Collection", - "HeaderAddToPlaylist": "Ajouter à la liste de lecture", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Obtenez Jellyfin Première", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Mode Cinéma", - "HeaderCloudSync": "Synchronisation Cloud", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continuer à regarder", - "HeaderConvertYourRecordings": "Convertir vos enregistrements", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Supprimer l'élément", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Applications Jellyfin gratuites", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "Mes Médias", - "HeaderMyMediaSmall": "Mes médias (petit)", - "HeaderNewRecording": "Nouvel enregistrement", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "À Suivre", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Média hors ligne", - "HeaderOfflineDownloadsDescription": "Téléchargez le média sur vos appareils pour une utilisation hors ligne facile.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Jouer mon média", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Télécommande", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Sélectionner une date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Aide", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} articles", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Country:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "Adresse courriel:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Langage:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Nom:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Liste de lecture:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Année:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "En direct", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Un abonnement Jellyfin Première actif est nécessaire pour créer des enregistrements automatiques en série.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Éléments ajoutés.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "Si vous avez un abonnement Jellyfin Première actif, assurez-vous d'avoir installé Jellyfin Première sur le tableau de bord de votre serveur Jellyfin, auquel vous pouvez accéder en cliquant sur Jellyfin Première dans le menu principal.", - "MessageUnlockAppWithPurchaseOrSupporter": "Déverrouillez cette fonctionnalité avec un petit achat unique ou avec un abonnement Jellyfin Premiere actif.", - "MessageUnlockAppWithSupporter": "Déverrouillez cette fonctionnalité avec un abonnement Jellyfin Première actif.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Lundi", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "Nouvelle Collection", - "NewCollectionHelp": "Les collections vous permettent de créer des regroupements personnalisés de films et d'autres contenus de la bibliothèque.", - "NewCollectionNameExample": "Exemple: Collection Star Wars", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "Aucun résultat trouvé.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "Nouveau...", - "Original": "Original", - "OriginalAirDateValue": "Date de diffusion originale: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Classement parentale", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Première", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Convertissez automatiquement des enregistrements en un format convivial avec Jellyfin Première. Les enregistrements seront rapidement convertis en MP4 ou MKV, en fonction des paramètres du serveur Jellyfin.", - "Quality": "Qualité", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Enregistrement", - "RecordSeries": "Record series", - "RecordingCancelled": "Enregistrement annulé.", - "RecordingScheduled": "Enregistrement programmé.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Rafraîchir", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Rafraîchir la file d'attente.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Répéter", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Samedi", - "Save": "Sauvegarder", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Rechercher", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Rechercher des sous-titres", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Série annulée.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Enregistrement en série programmé.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "Ce serveur Jellyfin doit être mis à jour. Pour télécharger la dernière version, veuillez visiter {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Partager", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Sous-titres", - "Suggestions": "Suggestions", - "Sunday": "Dimanche", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Jeudi", - "TrackCount": "{0} pistes", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Mardi", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Spécial - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Mercredi", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "D\u00e9verrouillez cette fonctionnalit\u00e9 avec un petit achat unique ou avec un abonnement Emby Premiere actif.", + "MessageUnlockAppWithSupporter": "D\u00e9verrouillez cette fonctionnalit\u00e9 avec un abonnement Emby Premi\u00e8re actif.", + "MessageToValidateSupporter": "Si vous avez un abonnement Emby Premi\u00e8re actif, assurez-vous d'avoir install\u00e9 Emby Premi\u00e8re sur le tableau de bord de votre serveur Emby, auquel vous pouvez acc\u00e9der en cliquant sur Emby Premi\u00e8re dans le menu principal.", + "ValueSpecialEpisodeName": "Sp\u00e9cial - {0}", + "Share": "Partager", + "Add": "Ajouter", + "ServerUpdateNeeded": "Ce serveur Emby doit \u00eatre mis \u00e0 jour. Pour t\u00e9l\u00e9charger la derni\u00e8re version, veuillez visiter {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "Nouveau", + "Premiere": "Premi\u00e8re", + "Live": "En direct", + "Repeat": "R\u00e9p\u00e9ter", + "TrackCount": "{0} pistes", + "ItemCount": "{0} articles", + "OriginalAirDateValue": "Date de diffusion originale: {0}", + "EndsAtValue": "Se termine \u00e0 {0}", + "HeaderSelectDate": "S\u00e9lectionner une date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Annuler", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "J'ai compris", + "ButtonRestart": "Red\u00e9marrer", + "RecordingCancelled": "Enregistrement annul\u00e9.", + "SeriesCancelled": "S\u00e9rie annul\u00e9e.", + "RecordingScheduled": "Enregistrement programm\u00e9.", + "SeriesRecordingScheduled": "Enregistrement en s\u00e9rie programm\u00e9.", + "HeaderNewRecording": "Nouvel enregistrement", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Dimanche", + "Monday": "Lundi", + "Tuesday": "Mardi", + "Wednesday": "Mercredi", + "Thursday": "Jeudi", + "Friday": "Vendredi", + "Saturday": "Samedi", + "Days": "Jours", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Mode Cin\u00e9ma", + "HeaderCloudSync": "Synchronisation Cloud", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "HeaderOfflineDownloads": "M\u00e9dia hors ligne", + "HeaderOfflineDownloadsDescription": "T\u00e9l\u00e9chargez le m\u00e9dia sur vos appareils pour une utilisation hors ligne facile.", + "CloudSyncFeatureDescription": "Synchronisez vos m\u00e9dias avec le Cloud pour faciliter la sauvegarde, l'archivage et la conversion.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "CinemaModeFeatureDescription": "Le Mode Cin\u00e9ma vous donne la v\u00e9ritable exp\u00e9rience cin\u00e9matographique avec des bandes annonces et des intros personnalis\u00e9s avant le film.", + "HeaderFreeApps": "Applications Emby gratuites", + "FreeAppsFeatureDescription": "Profitez de l'acc\u00e8s gratuit aux applications Emby pour vos appareils.", + "HeaderBecomeProjectSupporter": "Obtenez Emby Premi\u00e8re", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Un abonnement Emby Premi\u00e8re actif est n\u00e9cessaire pour cr\u00e9er des enregistrements automatiques en s\u00e9rie.", + "LabelEmailAddress": "Adresse courriel:", + "PromoConvertRecordingsToStreamingFormat": "Convertissez automatiquement des enregistrements en un format convivial avec Emby Premi\u00e8re. Les enregistrements seront rapidement convertis en MP4 ou MKV, en fonction des param\u00e8tres du serveur Emby.", + "FeatureRequiresEmbyPremiere": "Cette fonctionnalit\u00e9 n\u00e9cessite un abonnement Emby Premi\u00e8re actif.", + "HeaderConvertYourRecordings": "Convertir vos enregistrements", + "Record": "Enregistrement", + "Save": "Sauvegarder", + "Edit": "Modifier", + "Download": "T\u00e9l\u00e9charger", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Avanc\u00e9", + "Delete": "Supprimer", + "HeaderDeleteItem": "Supprimer l'\u00e9l\u00e9ment", + "ConfirmDeleteItem": "La suppression de cet \u00e9l\u00e9ment le supprimera \u00e0 la fois du syst\u00e8me de fichiers et de votre m\u00e9diath\u00e8que. \u00cates-vous s\u00fbr de vouloir continuer?", + "Refresh": "Rafra\u00eechir", + "RefreshQueued": "Rafra\u00eechir la file d'attente.", + "AddToCollection": "Ajouter \u00e0 la collection", + "HeaderAddToCollection": "Ajouter \u00e0 la Collection", + "NewCollection": "Nouvelle Collection", + "LabelCollection": "Collection:", + "Help": "Aide", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Les collections vous permettent de cr\u00e9er des regroupements personnalis\u00e9s de films et d'autres contenus de la biblioth\u00e8que.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Nom:", + "NewCollectionNameExample": "Exemple: Collection Star Wars", + "MessageItemsAdded": "\u00c9l\u00e9ments ajout\u00e9s.", + "OptionNew": "Nouveau...", + "LabelPlaylist": "Liste de lecture:", + "AddToPlaylist": "Ajouter \u00e0 la liste de lecture", + "HeaderAddToPlaylist": "Ajouter \u00e0 la liste de lecture", + "Subtitles": "Sous-titres", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Rechercher des sous-titres", + "LabelLanguage": "Langage:", + "Search": "Rechercher", + "NoSubtitleSearchResultsFound": "Aucun r\u00e9sultat trouv\u00e9.", + "File": "Fichier", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Ann\u00e9e:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Country:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Classement parentale", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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": "Jouer mon m\u00e9dia", + "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "T\u00e9l\u00e9commande", + "Disconnect": "Se d\u00e9connecter", + "EnableDisplayMirroring": "Activer l'affichage mirroir", + "HeaderPlayOn": "Play On", + "Quality": "Qualit\u00e9", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "Mes M\u00e9dias", + "HeaderMyMediaSmall": "Mes m\u00e9dias (petit)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continuer \u00e0 regarder", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "\u00c0 Suivre", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/fr.json b/src/bower_components/emby-webcomponents/strings/fr.json index 15aa3315a2..dd29b91f0d 100644 --- a/src/bower_components/emby-webcomponents/strings/fr.json +++ b/src/bower_components/emby-webcomponents/strings/fr.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolu", - "Accept": "Accepter", - "AccessRestrictedTryAgainLater": "L'accès est actuellement restreint. Veuillez réessayer plus tard.", - "Actor": "Acteur(trice)", - "Add": "Ajouter", - "AddToCollection": "Ajouter à la collection", - "AddToPlayQueue": "Ajouter à la file d'attente", - "AddToPlaylist": "Ajouter à la liste de lecture", - "AddedOnValue": "Ajouté le {0}", - "Advanced": "Avancé", - "AirDate": "Date de diffusion", - "Aired": "Diffusé", - "Albums": "Albums", - "All": "Tout", - "AllChannels": "Toutes les chaînes", - "AllComplexFormats": "Tous les formats complexes (ASS, SSA, VOBSUB, PGS, SUB/IDX etc)", - "AllEpisodes": "Tous les épisodes", - "AllLanguages": "Tous les langages", - "AllowSeasonalThemes": "Autoriser les thèmes saisonniers automatiques", - "AllowSeasonalThemesHelp": "Des thèmes saisonniers viendront occasionnellement remplacer votre thème régulier.", - "AlwaysPlaySubtitles": "Toujours lancer les sous-titres", - "AlwaysPlaySubtitlesHelp": "Les sous-titres correspondant à la préférence linguistique seront chargés indépendamment de la langue de l'audio.", - "AnamorphicVideoNotSupported": "Vidéo anamorphique non prise en charge", - "AndroidUnlockRestoreHelp": "Pour restaurer votre achat précédent, assurez-vous de vous connecter à l'appareil avec le même compte Google (ou Amazon) qui a effectué l'achat. Assurez-vous que la boutique d'applications est activée et n'est restreinte par aucun contrôle parental, et assurez-vous d'avoir une connexion Internet fonctionnelle. Vous n'aurez à le faire qu'une seule fois, pour restaurer votre achat précédent.", - "AnyLanguage": "N'importe quel langage", - "Anytime": "N'importe quand", - "AroundTime": "Aux environs de {0}", - "Art": "Art", - "Artists": "Artistes", - "AsManyAsPossible": "Autant que possible", - "Ascending": "Croissant", - "AspectRatio": "Ratio d'aspect original", - "AttemptingWakeServer": "Essai de réveil du serveur. Veuillez patienter...", - "AttributeNew": "Nouveau", - "AudioBitDepthNotSupported": "Profondeur des échantillons de l'audio non prise en charge", - "AudioBitrateNotSupported": "Débit audio non pris en charge", - "AudioChannelsNotSupported": "Canaux audio non prises en charge", - "AudioCodecNotSupported": "Codec audio non supporté", - "AudioProfileNotSupported": "Profil audio non pris en charge", - "AudioSampleRateNotSupported": "Taux d'échantillonnage audio non pris en charge", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (basé sur le réglage de la langue)", - "AutomaticallyConvertNewContent": "Convertir automatiquement les nouveaux contenus", - "AutomaticallyConvertNewContentHelp": "Les nouveaux contenus seront automatiquement convertis", - "AutomaticallySyncNewContent": "Télécharger automatiquement le nouveau contenu", - "AutomaticallySyncNewContentHelp": "Le nouveau contenu ajouté à ce dossier sera automatiquement transféré vers l'appareil.", - "Backdrop": "Arrière-plan", - "Backdrops": "Arrière-plans", - "Banner": "Bannière", - "BestFit": "Ajusté", - "BirthLocation": "Lieu de naissance", - "Books": "Livres", - "Box": "Boîtier", - "BoxRear": "Dos de boîtier", - "Browse": "Parcourir", - "BurnSubtitlesHelp": "Détermine si le serveur doit graver les sous-titres lors de la conversion vidéo en fonction du format des sous-titres. Éviter la gravure des sous-titres améliorera les performances du serveur. Sélectionnez Auto pour graver les formats basés sur l'image (par exemple, VOBSUB, PGS, SUB/IDX etc) ainsi que certains sous-titres ASS/SSA", - "ButtonCancel": "Annuler", - "ButtonGotIt": "Compris", - "ButtonOk": "OK", - "ButtonPlayOneMinute": "Lire une minute", - "ButtonRestart": "Redémarrer", - "ButtonRestorePreviousPurchase": "Restaurer l'achat", - "ButtonTryAgain": "Veuillez réessayer", - "ButtonUnlockPrice": "Déverrouiller {0}", - "ButtonUnlockWithPurchase": "Déverrouillez avec un achat", - "CancelDownload": "Annuler le téléchargement", - "CancelRecording": "Annuler l'enregistrement", - "CancelSeries": "Annuler la série", - "Categories": "Catégories", - "ChannelNameOnly": "Seulement la chaîne {0}", - "ChannelNumber": "Numéro de chaîne", - "CinemaModeConfigurationHelp": "Le mode cinéma apporte l'expérience du cinéma directement dans votre salon grâce à la possibilité de lire des bandes-annonces et des introductions personnalisées avant le film principal.", - "CinemaModeFeatureDescription": "Le mode cinéma apporte l'expérience du cinéma directement dans votre salon grâce à la possibilité de lire des bandes-annonces et des introductions personnalisées avant le film principal.", - "CloudSyncFeatureDescription": "Synchronisez vos médias vers le cloud pour le sauvegarder, l'archiver et le convertir facilement.", - "Collections": "Collections", - "ColorPrimaries": "Couleurs primaires", - "ColorSpace": "Espace colorimétrique", - "ColorTransfer": "Transfert de couleur", - "CommunityRating": "Note de la communauté", - "Composer": "Compositeur(trice)", - "ConfigureDateAdded": "Configurez comment la date d'ajout est déterminée dans le tableau de bord du serveur Jellyfin, dans Médiathèque, Avancé", - "ConfirmDeleteImage": "Supprimer l'image ?", - "ConfirmDeleteItem": "Supprimer cet élément l'effacera à la fois du système de fichiers et de votre médiathèque. Voulez-vous vraiment continuer ?", - "ConfirmDeleteItems": "Supprimer ces éléments les effacera à la fois du système de fichiers et de votre médiathèque. Voulez-vous vraiment continuer ?", - "ConfirmDeletion": "Confirmer la suppression", - "ConfirmEndPlayerSession": "Voulez-vous arrêter Jellyfin sur {0} ?", - "ConfirmRemoveDownload": "Supprimer le téléchargement ?", - "Connect": "Se connecter", - "ContainerBitrateExceedsLimit": "Le débit du média dépasse la limite.", - "ContainerNotSupported": "Conteneur non pris en charge", - "Continue": "Continuer", - "ContinueInSecondsValue": "Continuer dans {0} secondes.", - "ContinueWatching": "Continuez à regarder", - "Continuing": "En cours", - "Convert": "Convertir", - "ConvertItemLimitHelp": "Optionnel. Définir une limite de nombre d'éléments à convertir.", - "ConvertUnwatchedVideosOnly": "Convertir les vidéos non lues uniquement", - "ConvertUnwatchedVideosOnlyHelp": "Seulement les vidéos non lues seront converties", - "ConvertingDots": "Conversion...", - "Countries": "Pays", - "CriticRating": "Note de la critique", - "DateAdded": "Date d'ajout", - "DatePlayed": "Date de lecture", - "Days": "Jours", - "Default": "Par défaut", - "DefaultErrorMessage": "Il y a eu une erreur lors de l'exécution de la requête. Veuillez réessayer plus tard.", - "DefaultSubtitlesHelp": "Les sous-titres seront chargés selon les marqueurs par défaut et forcé dans les métadonnées intégrées. Les langues préférées seront utilisées quand plusieurs options seront disponibles.", - "Delete": "Supprimer", - "DeleteMedia": "Supprimer le média", - "Depressed": "Diminuer", - "Descending": "Décroissant", - "Desktop": "Bureau", - "DirectPlayError": "Erreur de lecture directe", - "DirectPlaying": "Lecture directe", - "DirectStreamHelp1": "Le média est compatible avec l'appareil en ce qui concerne la résolution et le type de média (H.264, AC3 etc), mais se trouve dans un conteneur de fichiers incompatible (.mkv, .avi, .wmv etc). La vidéo sera rempaquetée à la volée avant d'être diffusée à l'appareil.", - "DirectStreamHelp2": "Le streaming en direct d'un fichier utilise très peu de puissance de traitement sans perte de qualité vidéo.", - "DirectStreaming": "Streaming direct", - "Director": "Réalisateur(trice)", - "DirectorValue": "Réalisateur: {0}", - "DirectorsValue": "Réalisateurs: {0}", - "Disc": "Disque", - "Disconnect": "Déconnecter", - "Dislike": "Je n'aime pas", - "Display": "Affichage", - "DisplayInMyMedia": "Afficher sur l’écran d’accueil", - "DisplayInOtherHomeScreenSections": "Afficher dans les sections de l’écran d’accueil comme Ajouts récents et Reprendre", - "DisplayMissingEpisodesWithinSeasons": "Afficher les épisodes manquants dans les saisons", - "DisplayMissingEpisodesWithinSeasonsHelp": "Cette option doit aussi être activée pour les médiathèques TV dans les paramètres du serveur Jellyfin.", - "DisplayModeHelp": "Sélectionner le type d'écran sur lequel vous utilisez Jellyfin.", - "DoNotRecord": "Ne pas enregistrer", - "Down": "Bas", - "Download": "Téléchargement", - "DownloadItemLimitHelp": "Optionnel. Définir une limite de nombre d'éléments à télécharger.", - "Downloaded": "Téléchargé", - "Downloading": "Téléchargement en cours", - "DownloadingDots": "Téléchargement...", - "Downloads": "Téléchargements", - "DownloadsValue": "{0} téléchargements", - "DropShadow": "Ombre portée", - "DvrFeatureDescription": "Planifiez des enregistrements de TV en direct individuels, des enregistrements de séries et bien plus avec le magnétoscope Jellyfin.", - "DvrSubscriptionRequired": "Le magnétoscope Jellyfin nécessite un abonnement Jellyfin Premiere.", - "Edit": "Modifier", - "EditImages": "Modifier les images", - "EditMetadata": "Éditer les métadonnées", - "EditSubtitles": "Modifier les sous-titres", - "EnableBackdrops": "Activer les images d'arrière-plans", - "EnableBackdropsHelp": "Si activé, les images d'arrière-plan seront affichées sur certaines pages pendant la navigation dans la médiathèque.", - "EnableCinemaMode": "Activer le mode cinéma", - "EnableColorCodedBackgrounds": "Activer les fonds avec code couleur", - "EnableDisplayMirroring": "Activer le partage d'écran", - "EnableExternalVideoPlayers": "Activer les lecteurs vidéo externes", - "EnableExternalVideoPlayersHelp": "Une liste des lecteurs externes sera affichée au lancement de la lecture d'une vidéo.", - "EnableNextVideoInfoOverlay": "Activer les informations de la vidéo suivante pendant la lecture", - "EnableNextVideoInfoOverlayHelp": "À la fin d'une vidéo, afficher les informations sur la vidéo suivante dans la file d'attente.", - "EnableThemeSongs": "Activer les thèmes musicaux", - "EnableThemeSongsHelp": "Si activé, les thèmes musicaux seront lus en arrière-plan pendant la navigation dans la médiathèque.", - "EnableThemeVideos": "Activer les thèmes vidéos", - "EnableThemeVideosHelp": "Si activé, les thèmes vidéos seront lus en arrière-plan tout en parcourant la médiathèque.", - "Ended": "Terminé", - "EndsAtValue": "Se termine à {0}", - "Episodes": "Épisodes", - "Error": "Erreur", - "ErrorAddingGuestAccount1": "Une erreur est survenue lors de l'ajout du compte Jellyfin Connect. Vos invités ont-ils créé un compte Jellyfin ? Ils peuvent s'inscrire sur {0}.", - "ErrorAddingGuestAccount2": "Si le problème persiste, veuillez envoyer un courriel à {0} en précisant votre adresse courriel ainsi que la leur.", - "ErrorAddingJellyfinConnectAccount1": "Une erreur est survenue lors de l'ajout du compte Jellyfin Connect. Avez-vous créé un compte Jellyfin ? Inscrivez-vous sur {0}.", - "ErrorAddingJellyfinConnectAccount2": "Si le problème persiste, veuillez envoyer un courriel à {0} avec l'adresse utilisée lors de la création de votre compte Jellyfin.", - "ErrorConnectServerUnreachable": "Une erreur est survenue pendant l'exécution de l'opération demandée. Votre serveur est dans l'incapacité de joindre le serveur d'Jellyfin Connect à {0}. Veuillez vérifier que votre serveur est bien connecté à Internet et qu'aucun pare-feu ou autre logiciel de sécurité ne bloque les communications.", - "ErrorDeletingItem": "Une erreur s'est produite lors de la suppression de l'élément du serveur Jellyfin. Vérifiez que le serveur Jellyfin a un accès en écriture au dossier multimédia et réessayez.", - "ErrorReachingJellyfinConnect": "Une erreur est survenue pendant la connexion au serveur Jellyfin Connect. Veuillez vous assurer que vous avez une connexion internet active puis réessayez.", - "ErrorRemovingJellyfinConnectAccount": "Une erreur est survenue pendant la suppression du compte Jellyfin Connect. Veuillez vous assurer que vous avez une connexion internet active puis réessayez.", - "ExtraLarge": "Très grand", - "Extras": "Extras", - "Favorite": "Favori", - "Favorites": "Favoris", - "FeatureRequiresJellyfinPremiere": "Cette fonctionnalité nécessite un abonnement Jellyfin Premiere.", - "Features": "Longs métrages", - "File": "Fichier", - "Fill": "Remplir", - "Filters": "Filtres", - "Folders": "Dossiers", - "FormatValue": "Format : {0}", - "FreeAppsFeatureDescription": "Profitez d'un accès gratuit aux applications Jellyfin pour vos appareils.", - "Friday": "Vendredi", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Grouper par séries", - "GroupVersions": "Grouper les versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "Utilisateur non trouvé. Veuillez vérifier que le nom est correct et essayez à nouveau, ou essayez de renseigner l'adresse courriel.", - "Guide": "Guide", - "HDPrograms": "Programmes HD", - "HeaderActiveRecordings": "Enregistrements actifs", - "HeaderAddToCollection": "Ajouter à la collection", - "HeaderAddToPlaylist": "Ajouter à la liste de lecture", - "HeaderAddUpdateImage": "Ajouter/Mettre à jour une image", - "HeaderAlbumArtists": "Artistes de l'album", - "HeaderAlreadyPaid": "Vous avez déjà payé ?", - "HeaderAppearsOn": "Apparait dans", - "HeaderAudioBooks": "Livres audios", - "HeaderAudioSettings": "Réglages audio", - "HeaderBecomeProjectSupporter": "Obtenez Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Les avantages d'Jellyfin Premiere", - "HeaderCancelRecording": "Annuler l'enregistrement", - "HeaderCancelSeries": "Annuler la série", - "HeaderCinemaMode": "Mode cinéma", - "HeaderCloudSync": "Synchronisation avec le cloud", - "HeaderConfirmRecordingCancellation": "Confirmer l'annulation de l'enregistrement", - "HeaderContinueListening": "Reprendre l'écoute", - "HeaderContinueWatching": "Reprendre", - "HeaderConvertYourRecordings": "Convertissez vos enregistrements", - "HeaderCustomizeHomeScreen": "Personnaliser l'écran d'accueil", - "HeaderDeleteItem": "Supprimer l'élément", - "HeaderDeleteItems": "Supprimer les éléments", - "HeaderDisplaySettings": "Paramètres d'affichage", - "HeaderDownloadSettings": "Paramètres de téléchargement", - "HeaderEditImages": "Modifier les images", - "HeaderEnabledFields": "Activer les champs", - "HeaderEnabledFieldsHelp": "Décocher un champ pour le verrouiller et empêcher ses données d'être modifiées.", - "HeaderExternalIds": "Identifiants externes :", - "HeaderFavoriteAlbums": "Albums Favoris", - "HeaderFavoriteArtists": "Artistes Favoris", - "HeaderFavoriteCollections": "Collections Favorites", - "HeaderFavoriteEpisodes": "Episodes Favoris", - "HeaderFavoriteGames": "Jeux Favoris", - "HeaderFavoriteMovies": "Films Favoris", - "HeaderFavoritePlaylists": "Listes de lecture favorites", - "HeaderFavoriteShows": "Séries Favorites", - "HeaderFavoriteSongs": "Chansons Favorites", - "HeaderFavoriteVideos": "Vidéos favoris", - "HeaderFreeApps": "Applications Jellyfin gratuites", - "HeaderHomeScreen": "Écran d'accueil", - "HeaderIdentifyItemHelp": "Entrez un ou plusieurs critères de recherche. Retirez des critères pour élargir les résultats de la recherche.", - "HeaderInvitationSent": "Invitation envoyée", - "HeaderJellyfinAccountAdded": "Compte Jellyfin ajouté", - "HeaderJellyfinAccountRemoved": "Compte Jellyfin supprimé", - "HeaderKeepRecording": "Garder l'enregistrement", - "HeaderKeepSeries": "Garder la série", - "HeaderLatestChannelItems": "Derniers éléments de la chaîne", - "HeaderLatestChannelMedia": "Derniers éléments de la chaîne", - "HeaderLatestFrom": "{0}, ajouts récents", - "HeaderLatestMedia": "Derniers médias", - "HeaderLatestRecordings": "Derniers enregistrements", - "HeaderLearnMore": "En savoir plus", - "HeaderLibraryFolders": "Dossiers de la médiathèque", - "HeaderLibraryOrder": "Ordre de la médiathèque", - "HeaderMetadataSettings": "Paramètres des métadonnées", - "HeaderMusicQuality": "Qualité de la musique :", - "HeaderMyDevice": "Cet appareil", - "HeaderMyDownloads": "Mes téléchargements", - "HeaderMyMedia": "Mes Médias", - "HeaderMyMediaSmall": "Mes médias (Petit)", - "HeaderNewRecording": "Nouvel enregistrement", - "HeaderNextEpisodePlayingInValue": "Lecture du prochain épisode dans {0}", - "HeaderNextUp": "À suivre", - "HeaderNextVideoPlayingInValue": "Lecture de la prochaine vidéo dans {0}", - "HeaderOfflineDownloads": "Média hors ligne", - "HeaderOfflineDownloadsDescription": "Transférez vos médias vers vos appareils pour une utilisation hors ligne.", - "HeaderOnNow": "En ce moment", - "HeaderPhotoAlbums": "Albums photo", - "HeaderPlayMyMedia": "Lire mon média", - "HeaderPlayOn": "Jouer sur", - "HeaderPlaybackError": "Erreur de lecture", - "HeaderRecordingOptions": "Options d'enregistrement", - "HeaderRemoteControl": "Contrôle à distance", - "HeaderRestartingJellyfinServer": "Redémarrage du serveur Jellyfin", - "HeaderSaySomethingLike": "Dites quelque chose comme...", - "HeaderSecondsValue": "{0} secondes", - "HeaderSelectDate": "Sélectionnez la date", - "HeaderSeriesOptions": "Options de la série", - "HeaderSeriesStatus": "Statut de la série", - "HeaderSpecialEpisodeInfo": "Informations de l'épisode spécial", - "HeaderStartNow": "Commencer maintenant", - "HeaderStopRecording": "Arrêter l'enregistrement", - "HeaderSubtitleAppearance": "Apparence des sous-titres", - "HeaderSubtitleSettings": "Paramètres des sous-titres", - "HeaderSyncRequiresSub": "Le téléchargement nécessite un abonnement Jellyfin Premiere.", - "HeaderTermsOfPurchase": "Conditions d'achat", - "HeaderTryPlayback": "Essayer la lecture", - "HeaderUnlockFeature": "Déverrouiller la fonctionnalité", - "HeaderUploadImage": "Envoyer une image", - "HeaderVideoQuality": "Qualité vidéo", - "HeaderVideoType": "Type de vidéo", - "HeaderWaitingForWifi": "En attente du Wi-Fi", - "HeaderWakeServer": "Réveiller le serveur", - "HeaderYouSaid": "Vous avez dit...", - "Help": "Aide", - "Hide": "Cacher", - "HideWatchedContentFromLatestMedia": "Masquer le contenu déjà vu dans les derniers médias", - "Home": "Accueil", - "Horizontal": "Horizontal", - "HowDidYouPay": "Comment avez-vous payé ?", - "IHaveJellyfinPremiere": "J'ai Jellyfin Premiere", - "IPurchasedThisApp": "J'ai acheté cette application", - "Identify": "Identifier", - "Images": "Images", - "ImdbRating": "Note IMDb", - "InstallingPackage": "Installation de {0}", - "InstantMix": "Mix instantané", - "InterlacedVideoNotSupported": "Vidéo entrelacée non prise en charge", - "ItemCount": "{0} éléments", - "Items": "Éléments", - "KeepDownload": "Garder le téléchargement", - "KeepOnDevice": "Garder sur l'appareil", - "Kids": "Jeunesse", - "Label3DFormat": "Format 3D :", - "LabelAirDays": "Jours de diffusion :", - "LabelAirTime": "Heure de diffusion :", - "LabelAirsAfterSeason": "Diffusion après la saison :", - "LabelAirsBeforeEpisode": "Diffusion avant l'épisode :", - "LabelAirsBeforeSeason": "Diffusion avant la saison :", - "LabelAlbum": "Album :", - "LabelAlbumArtists": "Artistes de l'album :", - "LabelArtists": "Artistes :", - "LabelArtistsHelp": "Séparer les différents éléments par ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Langue audio préférée :", - "LabelBirthDate": "Date de naissance :", - "LabelBirthYear": "Année de naissance :", - "LabelBitrateMbps": "Débit (Mbps) :", - "LabelBurnSubtitles": "Graver les sous-titres :", - "LabelChannels": "Chaînes :", - "LabelCollection": "Collection :", - "LabelCommunityRating": "Note de la communauté :", - "LabelContentType": "Type de contenu :", - "LabelConvertTo": "Convertir en :", - "LabelCountry": "Pays :", - "LabelCriticRating": "Note des critiques :", - "LabelCustomRating": "Note personnalisée :", - "LabelDashboardTheme": "Thème du tableau de bord du serveur :", - "LabelDateAdded": "Date d'ajout :", - "LabelDateTimeLocale": "Date et heure locale :", - "LabelDeathDate": "Date de décès :", - "LabelDefaultScreen": "Écran par défaut", - "LabelDiscNumber": "Numéro de disque :", - "LabelDisplayLanguage": "Langue d'affichage :", - "LabelDisplayLanguageHelp": "La traduction d'Jellyfin est un projet en cours.", - "LabelDisplayMode": "Mode d'affichage :", - "LabelDisplayOrder": "Ordre d'affichage :", - "LabelDropImageHere": "Faites glisser l'image ici, ou cliquez pour parcourir vos fichiers.", - "LabelDropShadow": "Ombre portée :", - "LabelDynamicExternalId": "ID {0} :", - "LabelEmailAddress": "Adresse email :", - "LabelEndDate": "Date de fin :", - "LabelEpisodeNumber": "Numéro d'épisode :", - "LabelFont": "Police :", - "LabelHomeNetworkQuality": "Qualité du réseau local :", - "LabelHomeScreenSectionValue": "Section {0} de l'accueil :", - "LabelImageType": "Type d'image :", - "LabelInternetQuality": "Qualité d'internet :", - "LabelItemLimit": "Éléments maximum :", - "LabelKeep:": "Garder :", - "LabelKeepUpTo": "Garder jusqu'à :", - "LabelLanguage": "Langue :", - "LabelLockItemToPreventChanges": "Verrouiller cet élément pour éviter de futures modifications", - "LabelMaxChromecastBitrate": "Qualité maximum pour Chromecast :", - "LabelMetadataDownloadLanguage": "Langue de téléchargement préférée :", - "LabelName": "Nom :", - "LabelNumber": "Numéro :", - "LabelOriginalAspectRatio": "Ratio d'aspect original :", - "LabelOriginalTitle": "Titre original :", - "LabelOverview": "Synopsis :", - "LabelParentNumber": "Numéro du parent :", - "LabelParentalRating": "Classification parentale :", - "LabelPath": "Chemin :", - "LabelPersonRole": "Rôle :", - "LabelPersonRoleHelp": "Exemple : Chauffeur de camion de crème glacée", - "LabelPlaceOfBirth": "Lieu de naissance :", - "LabelPlayDefaultAudioTrack": "Utiliser le flux audio par défaut quelle que soit la langue", - "LabelPlaylist": "Liste de lecture :", - "LabelPreferredSubtitleLanguage": "Langue de sous-titrage préférée:", - "LabelProfile": "Profil :", - "LabelQuality": "Qualité :", - "LabelReasonForTranscoding": "Raison du transcodage :", - "LabelRecord": "Enregistrer :", - "LabelRefreshMode": "Mode d'actualisation :", - "LabelReleaseDate": "Date de sortie :", - "LabelRuntimeMinutes": "Durée (minutes) :", - "LabelScreensaver": "Économiseur d'écran :", - "LabelSeasonNumber": "Numéro de saison :", - "LabelSelectFolderGroups": "Grouper automatiquement le contenu des dossiers suivants dans des catégories telles que Films, Musique et TV :", - "LabelSelectFolderGroupsHelp": "Les dossiers qui ne sont pas cochés seront affichés tels quels, avec leur propre vue.", - "LabelShortOverview": "Résumé :", - "LabelSkin": "Habillage :", - "LabelSkipBackLength": "Durée des sauts en arrière :", - "LabelSkipForwardLength": "Durée des sauts en avant :", - "LabelSortBy": "Trier par :", - "LabelSortOrder": "Ordre de tri :", - "LabelSortTitle": "Titre de tri :", - "LabelSoundEffects": "Effets sonores :", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Commencer si possible :", - "LabelStatus": "État :", - "LabelStopWhenPossible": "Arrêter si possible :", - "LabelSubtitlePlaybackMode": "Mode des sous-titres :", - "LabelSubtitles": "Sous-titres:", - "LabelSyncJobName": "Nom de la tâche de synchronisation :", - "LabelSyncNoTargetsHelp": "Il semble que vous n'ayez actuellement aucune application qui supporte le téléchargement hors ligne.", - "LabelSyncTo": "Synchroniser avec :", - "LabelTVHomeScreen": "Écran d'accueil du mode TV :", - "LabelTagline": "Slogan :", - "LabelTextBackgroundColor": "Couleur de fond du texte :", - "LabelTextColor": "Couleur du texte :", - "LabelTextSize": "Taille du texte :", - "LabelTheme": "Thème :", - "LabelTitle": "Titre :", - "LabelTrackNumber": "Numéro de piste :", - "LabelType": "Type :", - "LabelVersion": "Version :", - "LabelVideo": "Vidéo:", - "LabelWebsite": "Site internet :", - "LabelWindowBackgroundColor": "Couleur de fond du texte :", - "LabelYear": "Année :", - "Large": "Grand", - "LatestFromLibrary": "{0}, ajouts récents", - "LearnHowYouCanContribute": "Voir comment vous pouvez contribuer.", - "LearnMore": "En savoir plus", - "Like": "J'aime", - "LinksValue": "Liens: {0}", - "List": "Liste", - "Live": "En direct", - "LiveBroadcasts": "Diffusions en direct", - "LiveTV": "TV en direct", - "LiveTvFeatureDescription": "Diffuser la TV en direct vers n'importe quelle application Jellyfin avec un tuner TV compatible installé sur votre serveur Jellyfin.", - "LiveTvRequiresUnlock": "La TV en direct nécessite un abonnement Jellyfin Premiere.", - "Logo": "Logo", - "ManageRecording": "Gérer l'enregistrement", - "MarkPlayed": "Marquer comme lu", - "MarkUnplayed": "Marquer comme non lu", - "MarkWatched": "Marquer comme lu", - "MediaIsBeingConverted": "Le média est converti en un format compatible avec l'appareil qui lit le média.", - "Medium": "Moyen", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Un abonnement Jellyfin Premiere est nécessaire pour créer des enregistrements de séries automatiques.", - "MessageAreYouSureDeleteSubtitles": "Voulez-vous vraiment supprimer ce fichier de sous-titres ?", - "MessageConfirmRecordingCancellation": "Annuler l'enregistrement ?", - "MessageDownloadQueued": "Téléchargement mis en file d'attente.", - "MessageFileReadError": "Une erreur est survenue lors de la lecture du fichier. Veuillez réessayer.", - "MessageIfYouBlockedVoice": "Si vous avez supprimé l'accès par commande vocale à l'application, vous devrez le reconfigurer avant de réessayer.", - "MessageInvitationSentToNewUser": "Un courriel a été envoyé à {0}, les invitant à s'inscrire à Jellyfin.", - "MessageInvitationSentToUser": "Un courriel a été envoyé à {0} avec votre invitation de partage.", - "MessageItemSaved": "Élément enregistré.", - "MessageItemsAdded": " Éléments ajoutés.", - "MessageJellyfinAccontRemoved": "Le compte Jellyfin a été supprimé pour cet utilisateur.", - "MessageJellyfinAccountAdded": "Le compte Jellyfin a été ajouté à cet utilisateur.", - "MessageLeaveEmptyToInherit": "Laisser vide pour hériter des paramètres de l'élément parent, ou de la valeur globale par défaut.", - "MessageNoDownloadsFound": "Aucun téléchargement hors ligne. Téléchargez votre contenu multimédia pour une utilisation hors ligne en cliquant sur Télécharger dans l'application.", - "MessageNoServersAvailableToConnect": "Connexion impossible, aucun serveur disponible. Si vous avez été invité à partager un serveur, veuillez accepter ci-dessous ou en cliquant sur le lien dans le courriel.", - "MessageNoSyncJobsFound": "Aucun téléchargement trouvé. Vous pouvez créer des tâches de téléchargement grâce aux boutons Télécharger présents dans l'application.", - "MessagePendingJellyfinAccountAdded": "Le compte Jellyfin a été ajouté à cet utilisateur. Un courriel sera envoyé au propriétaire du compte. Cette invitation devra être confirmée en cliquant sur un lien présent dans le courriel.", - "MessagePlayAccessRestricted": "La lecture de ce contenu est actuellement restreinte. Contactez l'administrateur de votre serveur Jellyfin pour plus d'informations.", - "MessageToValidateSupporter": "Si vous avez un abonnement Jellyfin Premiere, veuillez vous assurer que vous avez configuré Jellyfin Premiere dans le tableau de bord de votre serveur Jellyfin auquel vous pouvez accéder en cliquant sur Jellyfin Premiere dans le menu principal", - "MessageUnlockAppWithPurchaseOrSupporter": "Déverrouillez cette fonctionnalité avec un petit achat unique, ou avec un abonnement Jellyfin Premiere.", - "MessageUnlockAppWithSupporter": "Déverrouillez cette fonctionnalité avec un abonnement Jellyfin Premiere.", - "MessageWeDidntRecognizeCommand": "Désolé, cette commande n'a pas été reconnue.", - "MinutesAfter": "minutes après", - "MinutesBefore": "minutes avant", - "Mobile": "Mobile / Tablette", - "Monday": "Lundi", - "More": "Plus", - "MoveLeft": "Déplacer à gauche", - "MoveRight": "Déplacer à droite", - "Movies": "Films", - "MySubtitles": "Mes sous-titres", - "Name": "Nom", - "NewCollection": "Nouvelle collection", - "NewCollectionHelp": "Les collections vous permettent de créer des groupes personnalisés de films et d'autres contenus.", - "NewCollectionNameExample": "Exemple : Collection Star Wars", - "NewEpisodes": "Nouveaux épisodes", - "NewEpisodesOnly": "Uniquement les nouveaux épisodes", - "News": "Actualités", - "Next": "Prochain", - "No": "Non", - "NoItemsFound": "Aucun élément trouvé", - "NoSubtitleSearchResultsFound": "Aucun résultat trouvé.", - "NoSubtitles": "Pas de sous-titres", - "NoSubtitlesHelp": "Les sous-titres ne seront pas chargés par défaut. Ils peuvent toujours être activés manuellement pendant la lecture.", - "None": "Aucun", - "Normal": "Normal", - "Off": "Désactivés", - "OneChannel": "Une chaîne", - "OnlyForcedSubtitles": "Seulement les sous-titres forcés", - "OnlyForcedSubtitlesHelp": "Seuls les sous-titres marqués comme forcés seront chargés.", - "OnlyImageFormats": "Seulement les formats image (VOBSUB, PGS, SUB/IDX etc)", - "Open": "Ouvrir", - "OptionNew": "Nouveau...", - "Original": "Original", - "OriginalAirDateValue": "Date de diffusion originale : {0}", - "Overview": "Synopsis", - "PackageInstallCancelled": "L'installation de {0} a été annulée.", - "PackageInstallCompleted": "L'installation de {0} est terminée.", - "PackageInstallFailed": "L'installation de {0} a échoué.", - "ParentalRating": "Classification parentale", - "People": "Personnes", - "PerfectMatch": "Correspondance parfaite", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Mettre vos chaînes favorites au début", - "Play": "Lire", - "PlayAllFromHere": "Tout lire à partir d'ici", - "PlayCount": "Nombre de lectures", - "PlayFromBeginning": "Lire depuis le début", - "PlayNext": "Lire le suivant", - "PlayNextEpisodeAutomatically": "Lancer l'épisode suivant automatiquement", - "PlaybackErrorNoCompatibleStream": "Aucun flux compatible n'est actuellement disponible. Veuillez réessayer plus tard ou contactez votre administrateur système pour plus de détails.", - "PlaybackErrorNotAllowed": "Vous n'êtes pas autorisé à lire ce contenu. Veuillez contacter votre administrateur système pour plus de détails.", - "PlaybackErrorPlaceHolder": "Veuillez insérer le disque pour lire cette vidéo.", - "PlaybackSettings": "Paramètres de lecture", - "PlaybackSettingsIntro": "Pour configurer les réglages de lecture par défaut, arrêtez la lecture de la vidéo, puis cliquez sur votre icône utilisateur située en haut à droite dans l'application.", - "Played": "Lu", - "Playlists": "Listes de lecture", - "PleaseEnterNameOrId": "Veuillez saisir un nom ou un identifiant externe.", - "PleaseRestartServerName": "Veuillez redémarrer le serveur Jellyfin - {0}.", - "PleaseSelectDeviceToSyncTo": "Veuillez sélectionner l'appareil auquel le téléchargement doit être envoyé.", - "PleaseSelectTwoItems": "Veuillez sélectionner au moins deux éléments.", - "Premiere": "Premiere", - "Premieres": "Inédits", - "Previous": "Précédent", - "Primary": "Principal", - "PrivacyPolicy": "Politique de confidentialité", - "Producer": "Producteur(trice)", - "ProductionLocations": "Sites de production", - "Programs": "Programmes", - "PromoConvertRecordingsToStreamingFormat": "Convertissez automatiquement vos enregistrements en un format compatible avec le streaming avec Jellyfin Premiere. Les enregistrements seront convertis à la volée en MP4 ou MKV, selon les réglages du serveur Jellyfin.", - "Quality": "Qualité", - "QueueAllFromHere": "Tout mettre en file d'attente à partir d'ici", - "Raised": "Augmenter", - "RecentlyWatched": "Lu récemment", - "Record": "Enregistrer", - "RecordSeries": "Enregistrer la série", - "RecordingCancelled": "Enregistrement annulé.", - "RecordingScheduled": "Enregistrement planifié.", - "Recordings": "Enregistrements", - "RefFramesNotSupported": "Nombre d'images de référence de la vidéo non pris en charge", - "Refresh": "Actualiser", - "RefreshDialogHelp": "Les métadonnées sont actualisées en fonction des paramètres et des services Internet qui sont activés dans le tableau de bord du serveur Jellyfin.", - "RefreshMetadata": "Actualiser les métadonnées", - "RefreshQueued": "Actualisation mise en file d'attente.", - "Reject": "Refuser", - "ReleaseDate": "Date de sortie", - "RemoveDownload": "Supprimer le téléchargement", - "RemoveFromCollection": "Supprimer de la collection", - "RemoveFromPlaylist": "Supprimer de la liste de lecture", - "RemovingFromDevice": "Suppression de l'appareil", - "Repeat": "Répéter", - "RepeatAll": "Tout répéter", - "RepeatEpisodes": "Rediffusions", - "RepeatMode": "Mode de répétition", - "RepeatOne": "Répéter un média", - "ReplaceAllMetadata": "Remplacer toutes les métadonnées", - "ReplaceExistingImages": "Remplacer les images existantes", - "RestartPleaseWaitMessage": "Veuillez patienter pendant que le serveur Jellyfin s'arrête et redémarre. Cela peut prendre une minute ou deux.", - "ResumeAt": "Reprendre à {0}", - "Retry": "Réessayer", - "RunAtStartup": "Exécuter au démarrage", - "Runtime": "Durée", - "Saturday": "Samedi", - "Save": "Sauvegarder", - "ScanForNewAndUpdatedFiles": "Actualiser pour détecter les nouveaux fichiers et les modifications", - "Schedule": "Planning", - "Screenshot": "Capture d'écran", - "Screenshots": "Captures d'écran", - "Search": "Recherche", - "SearchForCollectionInternetMetadata": "Rechercher sur Internet les images et les métadonnées", - "SearchForMissingMetadata": "Rechercher les métadonnées manquantes", - "SearchForSubtitles": "Rechercher des sous-titres", - "SearchResults": "Résultats de la recherche", - "SecondaryAudioNotSupported": "Commutation de piste audio non prise en charge", - "SeriesCancelled": "Série annulée.", - "SeriesDisplayOrderHelp": "Ranger les épisodes par date de diffusion, par ordre de DVD ou par numéro absolu.", - "SeriesRecordingScheduled": "Enregistrement de la série planifié.", - "SeriesSettings": "Paramètres de la série", - "SeriesYearToPresent": "{0} - Présent", - "ServerNameIsRestarting": "Serveur Jellyfin - {0} redémarre.", - "ServerNameIsShuttingDown": "Serveur Jellyfin - {0} s'arrête.", - "ServerUpdateNeeded": "Le serveur Jellyfin doit être mis à jour. Pour télécharger la dernière version, veuillez visiter {0}", - "Settings": "Paramètres", - "SettingsSaved": "Paramètres enregistrés.", - "Share": "Partager", - "ShowIndicatorsFor": "Montrer les indicateurs pour :", - "ShowTitle": "Montrer le titre", - "ShowYear": "Voir l'année", - "Shows": "Émissions", - "Shuffle": "Aléatoire", - "SkipEpisodesAlreadyInMyLibrary": "Ne pas enregistrer les épisodes déjà présents dans ma médiathèque", - "SkipEpisodesAlreadyInMyLibraryHelp": "Les épisodes seront comparés en utilisant le numéro de saison et le numéro d'épisode, s'ils sont disponibles.", - "Small": "Petit", - "SmallCaps": "Petites majuscules", - "Smaller": "Plus petit", - "Smart": "Intelligent", - "SmartSubtitlesHelp": "Les sous-titres correspondant à la langue préférée seront chargés lorsque l'audio est dans une langue étrangère.", - "Songs": "Chansons", - "Sort": "Tri", - "SortByValue": "Trier par {0}", - "SortChannelsBy": "Trier les chaînes par :", - "SortName": "Nom de tri", - "Sports": "Sports", - "StatsForNerds": "Statistiques pour les geeks", - "StopRecording": "Arrêter l'enregistrement", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Ces paramètres s'appliquent également à toute lecture Chromecast démarrée par cet appareil.", - "SubtitleAppearanceSettingsDisclaimer": "Ces paramètres ne s'appliqueront pas aux sous-titres graphiques (PGS, DVD etc) ou aux sous-titres qui ont leurs propres styles incorporés (ASS/SSA).", - "SubtitleCodecNotSupported": "Format des sous-titres non pris en charge", - "SubtitleSettings": "Paramètres des sous-titres", - "SubtitleSettingsIntro": "Pour configurer l'apparence des sous-titres et la langue par défaut, arrêtez la lecture de la vidéo, puis cliquez sur votre icône utilisateur située en haut à droite dans l'application.", - "Subtitles": "Sous-titres", - "Suggestions": "Suggestions", - "Sunday": "Dimanche", - "Sync": "Synchroniser", - "SyncJobItemStatusCancelled": "Annulé", - "SyncJobItemStatusConverting": "Conversion en cours", - "SyncJobItemStatusFailed": "Échoué", - "SyncJobItemStatusQueued": "Mis en file d'attente", - "SyncJobItemStatusReadyToTransfer": "Prêt pour le transfert", - "SyncJobItemStatusRemovedFromDevice": "Supprimé de l'appareil", - "SyncJobItemStatusSynced": "Téléchargé", - "SyncJobItemStatusSyncedMarkForRemoval": "Suppression de l'appareil", - "SyncJobItemStatusTransferring": "Transfert en cours", - "SyncUnwatchedVideosOnly": "Télécharger seulement les vidéos non lues", - "SyncUnwatchedVideosOnlyHelp": "Seule les vidéos non lues seront téléchargées et les vidéos seront supprimées de l'appareil au fur et à mesure que vous les regardez.", - "SyncingDots": "Synchronisation...", - "TV": "TV", - "Tags": "Étiquettes", - "TagsValue": "Mots clés: {0}", - "TermsOfUse": "Conditions d'utilisation", - "ThankYouForTryingEnjoyOneMinute": "Profitez d'une minute de lecture. Merci d'avoir essayé Jellyfin.", - "ThemeSongs": "Chansons thématiques", - "ThemeVideos": "Vidéos thématiques", - "TheseSettingsAffectSubtitlesOnThisDevice": "Ces paramètres affectent les sous-titres de cet appareil", - "Thumb": "Vignette", - "Thursday": "Jeudi", - "TrackCount": "{0} pistes", - "Trailer": "Bande-annonce", - "Trailers": "Bandes-annonces", - "Transcoding": "Transcodage", - "TryMultiSelect": "Essayer la sélection multiple", - "TryMultiSelectMessage": "Pour modifier plusieurs médias, il suffit de cliquer et maintenir le clic sur n'importe quelle affiche, puis de sélectionner les autres éléments que vous voulez modifier. Essayez donc !", - "Tuesday": "Mardi", - "Uniform": "Uniforme", - "UnlockGuide": "Déverrouiller le guide", - "Unplayed": "Non lu", - "Unrated": "Non noté", - "UntilIDelete": "Jusqu'à ce que je le supprime", - "UntilSpaceNeeded": "Jusqu'à ce que l'espace disque soit nécessaire", - "Up": "Haut", - "Upload": "Envoyer", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disque {0}", - "ValueEpisodeCount": "{0} épisodes", - "ValueGameCount": "{0} jeux", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} films", - "ValueMusicVideoCount": "{0} vidéos musicales", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 épisode", - "ValueOneGame": "1 jeu", - "ValueOneItem": "1 élément", - "ValueOneMovie": "1 film", - "ValueOneMusicVideo": "1 vidéo musicale", - "ValueOneSeries": "1 série", - "ValueOneSong": "1 chanson", - "ValueSeconds": "{0} secondes", - "ValueSeriesCount": "{0} séries", - "ValueSongCount": "{0} chansons", - "ValueSpecialEpisodeName": "Spécial - {0}", - "Vertical": "Verticale", - "VideoBitDepthNotSupported": "Profondeur des couleurs de la vidéo non prise en charge", - "VideoCodecNotSupported": "Codec vidéo non supporté", - "VideoFramerateNotSupported": "Nombre d'images par seconde de la vidéo non pris en charge", - "VideoLevelNotSupported": "Niveau vidéo non pris en charge", - "VideoProfileNotSupported": "Profil vidéo non pris en charge", - "VideoRange": "Gamme vidéo", - "VideoResolutionNotSupported": "Résolution vidéo non prise en charge", - "ViewAlbum": "Voir l'album", - "ViewArtist": "Voir l'artiste", - "VoiceInput": "Entrée vocale", - "WakeServer": "Réveiller le serveur", - "WakeServerError": "Des paquets Wake-On-LAN on été envoyé à votre serveur, mais nous ne pouvons pas nous connecter à votre serveur Jellyfin. Votre machine a peut-être besoin de plus de temps pour se réveiller, ou le serveur Jellyfin n'est peut-être pas lancé sur la machine.", - "WakeServerSuccess": "Réussi !", - "Watched": "Lu", - "Wednesday": "Mercredi", - "WifiRequiredToDownload": "Une connexion Wi-Fi est nécessaire pour continuer le téléchargement.", - "Writer": "Scénariste", - "Yes": "Oui" -} + "PlaybackSettings": "Param\u00e8tres de lecture", + "SubtitleSettings": "Param\u00e8tres des sous-titres", + "MessageUnlockAppWithPurchaseOrSupporter": "D\u00e9verrouillez cette fonctionnalit\u00e9 avec un petit achat unique, ou avec un abonnement Emby Premiere.", + "MessageUnlockAppWithSupporter": "D\u00e9verrouillez cette fonctionnalit\u00e9 avec un abonnement Emby Premiere.", + "MessageToValidateSupporter": "Si vous avez un abonnement Emby Premiere, veuillez vous assurer que vous avez configur\u00e9 Emby Premiere dans le tableau de bord de votre serveur Emby auquel vous pouvez acc\u00e9der en cliquant sur Emby Premiere dans le menu principal", + "ValueSpecialEpisodeName": "Sp\u00e9cial - {0}", + "Share": "Partager", + "Add": "Ajouter", + "ServerUpdateNeeded": "Le serveur Emby doit \u00eatre mis \u00e0 jour. Pour t\u00e9l\u00e9charger la derni\u00e8re version, veuillez visiter {0}", + "LiveTvRequiresUnlock": "La TV en direct n\u00e9cessite un abonnement Emby Premiere.", + "AttributeNew": "Nouveau", + "Premiere": "Premiere", + "Live": "En direct", + "Repeat": "R\u00e9p\u00e9ter", + "TrackCount": "{0} pistes", + "ItemCount": "{0} \u00e9l\u00e9ments", + "OriginalAirDateValue": "Date de diffusion originale\u00a0: {0}", + "EndsAtValue": "Se termine \u00e0 {0}", + "HeaderSelectDate": "S\u00e9lectionnez la date", + "Watched": "Lu", + "AirDate": "Date de diffusion", + "Played": "Lu", + "ButtonOk": "OK", + "ButtonCancel": "Annuler", + "AccessRestrictedTryAgainLater": "L'acc\u00e8s est actuellement restreint. Veuillez r\u00e9essayer plus tard.", + "ButtonGotIt": "Compris", + "ButtonRestart": "Red\u00e9marrer", + "RecordingCancelled": "Enregistrement annul\u00e9.", + "SeriesCancelled": "S\u00e9rie annul\u00e9e.", + "RecordingScheduled": "Enregistrement planifi\u00e9.", + "SeriesRecordingScheduled": "Enregistrement de la s\u00e9rie planifi\u00e9.", + "HeaderNewRecording": "Nouvel enregistrement", + "WakeServer": "R\u00e9veiller le serveur", + "HeaderWakeServer": "R\u00e9veiller le serveur", + "AttemptingWakeServer": "Essai de r\u00e9veil du serveur. Veuillez patienter...", + "WakeServerSuccess": "R\u00e9ussi\u00a0!", + "HeaderCustomizeHomeScreen": "Personnaliser l'\u00e9cran d'accueil", + "WakeServerError": "Des paquets Wake-On-LAN on \u00e9t\u00e9 envoy\u00e9 \u00e0 votre serveur, mais nous ne pouvons pas nous connecter \u00e0 votre serveur Emby. Votre machine a peut-\u00eatre besoin de plus de temps pour se r\u00e9veiller, ou le serveur Emby n'est peut-\u00eatre pas lanc\u00e9 sur la machine.", + "Sunday": "Dimanche", + "Monday": "Lundi", + "Tuesday": "Mardi", + "Wednesday": "Mercredi", + "Thursday": "Jeudi", + "Friday": "Vendredi", + "Saturday": "Samedi", + "Days": "Jours", + "SortByValue": "Trier par {0}", + "LabelSortBy": "Trier par :", + "LabelSortOrder": "Ordre de tri :", + "HeaderPhotoAlbums": "Albums photo", + "Photos": "Photos", + "HeaderAppearsOn": "Apparait dans", + "List": "Liste", + "RecordSeries": "Enregistrer la s\u00e9rie", + "HeaderCinemaMode": "Mode cin\u00e9ma", + "HeaderCloudSync": "Synchronisation avec le cloud", + "Downloads": "T\u00e9l\u00e9chargements", + "HeaderMyDownloads": "Mes t\u00e9l\u00e9chargements", + "HeaderOfflineDownloads": "M\u00e9dia hors ligne", + "HeaderOfflineDownloadsDescription": "Transf\u00e9rez vos m\u00e9dias vers vos appareils pour une utilisation hors ligne.", + "CloudSyncFeatureDescription": "Synchronisez vos m\u00e9dias vers le cloud pour le sauvegarder, l'archiver et le convertir facilement.", + "LiveTvFeatureDescription": "Diffuser la TV en direct vers n'importe quelle application Emby avec un tuner TV compatible install\u00e9 sur votre serveur Emby.", + "DvrFeatureDescription": "Planifiez des enregistrements de TV en direct individuels, des enregistrements de s\u00e9ries et bien plus avec le magn\u00e9toscope Emby.", + "CinemaModeFeatureDescription": "Le mode cin\u00e9ma apporte l'exp\u00e9rience du cin\u00e9ma directement dans votre salon gr\u00e2ce \u00e0 la possibilit\u00e9 de lire des bandes-annonces et des introductions personnalis\u00e9es avant le film principal.", + "HeaderFreeApps": "Applications Emby gratuites", + "FreeAppsFeatureDescription": "Profitez d'un acc\u00e8s gratuit aux applications Emby pour vos appareils.", + "HeaderBecomeProjectSupporter": "Obtenez Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Un abonnement Emby Premiere est n\u00e9cessaire pour cr\u00e9er des enregistrements de s\u00e9ries automatiques.", + "LabelEmailAddress": "Adresse email :", + "PromoConvertRecordingsToStreamingFormat": "Convertissez automatiquement vos enregistrements en un format compatible avec le streaming avec Emby Premiere. Les enregistrements seront convertis \u00e0 la vol\u00e9e en MP4 ou MKV, selon les r\u00e9glages du serveur Emby.", + "FeatureRequiresEmbyPremiere": "Cette fonctionnalit\u00e9 n\u00e9cessite un abonnement Emby Premiere.", + "HeaderConvertYourRecordings": "Convertissez vos enregistrements", + "Record": "Enregistrer", + "Save": "Sauvegarder", + "Edit": "Modifier", + "Download": "T\u00e9l\u00e9chargement", + "Downloaded": "T\u00e9l\u00e9charg\u00e9", + "Downloading": "T\u00e9l\u00e9chargement en cours", + "Advanced": "Avanc\u00e9", + "Delete": "Supprimer", + "HeaderDeleteItem": "Supprimer l'\u00e9l\u00e9ment", + "ConfirmDeleteItem": "Supprimer cet \u00e9l\u00e9ment l'effacera \u00e0 la fois du syst\u00e8me de fichiers et de votre m\u00e9diath\u00e8que. Voulez-vous vraiment continuer ?", + "Refresh": "Actualiser", + "RefreshQueued": "Actualisation mise en file d'attente.", + "AddToCollection": "Ajouter \u00e0 la collection", + "HeaderAddToCollection": "Ajouter \u00e0 la collection", + "NewCollection": "Nouvelle collection", + "LabelCollection": "Collection\u00a0:", + "Help": "Aide", + "LabelDisplayMode": "Mode d'affichage :", + "Desktop": "Bureau", + "Mobile": "Mobile \/ Tablette", + "TV": "TV", + "DisplayModeHelp": "S\u00e9lectionner le type d'\u00e9cran sur lequel vous utilisez Emby.", + "LabelDisplayLanguage": "Langue d'affichage :", + "LabelDisplayLanguageHelp": "La traduction d'Emby est un projet en cours.", + "LearnHowYouCanContribute": "Voir comment vous pouvez contribuer.", + "NewCollectionHelp": "Les collections vous permettent de cr\u00e9er des groupes personnalis\u00e9s de films et d'autres contenus.", + "SearchForCollectionInternetMetadata": "Rechercher sur Internet les images et les m\u00e9tadonn\u00e9es", + "DisplayMissingEpisodesWithinSeasons": "Afficher les \u00e9pisodes manquants dans les saisons", + "DisplayMissingEpisodesWithinSeasonsHelp": "Cette option doit aussi \u00eatre activ\u00e9e pour les m\u00e9diath\u00e8ques TV dans les param\u00e8tres du serveur Emby.", + "EnableThemeSongs": "Activer les th\u00e8mes musicaux", + "EnableBackdrops": "Activer les images d'arri\u00e8re-plans", + "EnableThemeSongsHelp": "Si activ\u00e9, les th\u00e8mes musicaux seront lus en arri\u00e8re-plan pendant la navigation dans la m\u00e9diath\u00e8que.", + "EnableBackdropsHelp": "Si activ\u00e9, les images d'arri\u00e8re-plan seront affich\u00e9es sur certaines pages pendant la navigation dans la m\u00e9diath\u00e8que.", + "EnableThemeVideos": "Activer les th\u00e8mes vid\u00e9os", + "EnableThemeVideosHelp": "Si activ\u00e9, les th\u00e8mes vid\u00e9os seront lus en arri\u00e8re-plan tout en parcourant la m\u00e9diath\u00e8que.", + "RunAtStartup": "Ex\u00e9cuter au d\u00e9marrage", + "LabelScreensaver": "\u00c9conomiseur d'\u00e9cran\u00a0:", + "LabelSoundEffects": "Effets sonores\u00a0:", + "LabelSkin": "Habillage\u00a0:", + "LabelName": "Nom\u00a0:", + "NewCollectionNameExample": "Exemple\u00a0: Collection Star Wars", + "MessageItemsAdded": " \u00c9l\u00e9ments ajout\u00e9s.", + "OptionNew": "Nouveau...", + "LabelPlaylist": "Liste de lecture :", + "AddToPlaylist": "Ajouter \u00e0 la liste de lecture", + "HeaderAddToPlaylist": "Ajouter \u00e0 la liste de lecture", + "Subtitles": "Sous-titres", + "LabelTheme": "Th\u00e8me\u00a0:", + "LabelDashboardTheme": "Th\u00e8me du tableau de bord du serveur\u00a0:", + "SearchForSubtitles": "Rechercher des sous-titres", + "LabelLanguage": "Langue\u00a0:", + "Search": "Recherche", + "NoSubtitleSearchResultsFound": "Aucun r\u00e9sultat trouv\u00e9.", + "File": "Fichier", + "MessageAreYouSureDeleteSubtitles": "Voulez-vous vraiment supprimer ce fichier de sous-titres ?", + "ConfirmDeletion": "Confirmer la suppression", + "MySubtitles": "Mes sous-titres", + "MessageDownloadQueued": "T\u00e9l\u00e9chargement mis en file d'attente.", + "EditSubtitles": "Modifier les sous-titres", + "UnlockGuide": "D\u00e9verrouiller le guide", + "RefreshMetadata": "Actualiser les m\u00e9tadonn\u00e9es", + "ReplaceExistingImages": "Remplacer les images existantes", + "ReplaceAllMetadata": "Remplacer toutes les m\u00e9tadonn\u00e9es", + "SearchForMissingMetadata": "Rechercher les m\u00e9tadonn\u00e9es manquantes", + "LabelRefreshMode": "Mode d'actualisation\u00a0:", + "NoItemsFound": "Aucun \u00e9l\u00e9ment trouv\u00e9", + "HeaderSaySomethingLike": "Dites quelque chose comme...", + "ButtonTryAgain": "Veuillez r\u00e9essayer", + "HeaderYouSaid": "Vous avez dit...", + "MessageWeDidntRecognizeCommand": "D\u00e9sol\u00e9, cette commande n'a pas \u00e9t\u00e9 reconnue.", + "MessageIfYouBlockedVoice": "Si vous avez supprim\u00e9 l'acc\u00e8s par commande vocale \u00e0 l'application, vous devrez le reconfigurer avant de r\u00e9essayer.", + "ValueDiscNumber": "Disque {0}", + "Unrated": "Non not\u00e9", + "Favorite": "Favori", + "Like": "J'aime", + "Dislike": "Je n'aime pas", + "RefreshDialogHelp": "Les m\u00e9tadonn\u00e9es sont actualis\u00e9es en fonction des param\u00e8tres et des services Internet qui sont activ\u00e9s dans le tableau de bord du serveur Emby.", + "Open": "Ouvrir", + "Play": "Lire", + "AddToPlayQueue": "Ajouter \u00e0 la file d'attente", + "Shuffle": "Al\u00e9atoire", + "Identify": "Identifier", + "EditImages": "Modifier les images", + "EditMetadata": "\u00c9diter les m\u00e9tadonn\u00e9es", + "Convert": "Convertir", + "Sync": "Synchroniser", + "InstantMix": "Mix instantan\u00e9", + "ViewAlbum": "Voir l'album", + "ViewArtist": "Voir l'artiste", + "QueueAllFromHere": "Tout mettre en file d'attente \u00e0 partir d'ici", + "PlayAllFromHere": "Tout lire \u00e0 partir d'ici", + "PlayFromBeginning": "Lire depuis le d\u00e9but", + "ResumeAt": "Reprendre \u00e0 {0}", + "RemoveFromPlaylist": "Supprimer de la liste de lecture", + "RemoveFromCollection": "Supprimer de la collection", + "Sort": "Tri", + "Trailer": "Bande-annonce", + "MarkPlayed": "Marquer comme lu", + "MarkUnplayed": "Marquer comme non lu", + "GroupVersions": "Grouper les versions", + "PleaseSelectTwoItems": "Veuillez s\u00e9lectionner au moins deux \u00e9l\u00e9ments.", + "TryMultiSelect": "Essayer la s\u00e9lection multiple", + "TryMultiSelectMessage": "Pour modifier plusieurs m\u00e9dias, il suffit de cliquer et maintenir le clic sur n'importe quelle affiche, puis de s\u00e9lectionner les autres \u00e9l\u00e9ments que vous voulez modifier. Essayez donc !", + "HeaderConfirmRecordingCancellation": "Confirmer l'annulation de l'enregistrement", + "MessageConfirmRecordingCancellation": "Annuler l'enregistrement\u00a0?", + "Error": "Erreur", + "VoiceInput": "Entr\u00e9e vocale", + "LabelContentType": "Type de contenu :", + "LabelPath": "Chemin\u00a0:", + "Playlists": "Listes de lecture", + "LabelTitle": "Titre\u00a0:", + "LabelOriginalTitle": "Titre original\u00a0:", + "LabelSortTitle": "Titre de tri\u00a0:", + "LabelDateAdded": "Date d'ajout\u00a0:", + "DateAdded": "Date d'ajout", + "DatePlayed": "Date de lecture", + "ConfigureDateAdded": "Configurez comment la date d'ajout est d\u00e9termin\u00e9e dans le tableau de bord du serveur Emby, dans M\u00e9diath\u00e8que, Avanc\u00e9", + "LabelStatus": "\u00c9tat\u00a0:", + "LabelArtists": "Artistes\u00a0:", + "LabelArtistsHelp": "S\u00e9parer les diff\u00e9rents \u00e9l\u00e9ments par ;", + "HeaderAlbumArtists": "Artistes de l'album", + "LabelAlbumArtists": "Artistes de l'album :", + "LabelAlbum": "Album :", + "Artists": "Artistes", + "ImdbRating": "Note IMDb", + "CommunityRating": "Note de la communaut\u00e9", + "LabelCommunityRating": "Note de la communaut\u00e9\u00a0:", + "LabelCriticRating": "Note des critiques\u00a0:", + "CriticRating": "Note de la critique", + "LabelWebsite": "Site internet\u00a0:", + "LabelTagline": "Slogan\u00a0:", + "LabelOverview": "Synopsis\u00a0:", + "LabelShortOverview": "R\u00e9sum\u00e9\u00a0:", + "LabelReleaseDate": "Date de sortie\u00a0:", + "LabelYear": "Ann\u00e9e :", + "LabelPlaceOfBirth": "Lieu de naissance :", + "Aired": "Diffus\u00e9", + "LabelAirDays": "Jours de diffusion\u00a0:", + "LabelAirTime": "Heure de diffusion :", + "LabelRuntimeMinutes": "Dur\u00e9e (minutes)\u00a0:", + "LabelParentalRating": "Classification parentale\u00a0:", + "LabelCustomRating": "Note personnalis\u00e9e\u00a0:", + "LabelOriginalAspectRatio": "Ratio d'aspect original\u00a0:", + "Label3DFormat": "Format 3D\u00a0:", + "FormatValue": "Format : {0}", + "DownloadsValue": "{0} t\u00e9l\u00e9chargements", + "PerfectMatch": "Correspondance parfaite", + "EnableExternalVideoPlayers": "Activer les lecteurs vid\u00e9o externes", + "EnableExternalVideoPlayersHelp": "Une liste des lecteurs externes sera affich\u00e9e au lancement de la lecture d'une vid\u00e9o.", + "HeaderSpecialEpisodeInfo": "Informations de l'\u00e9pisode sp\u00e9cial", + "LabelAirsBeforeSeason": "Diffusion avant la saison :", + "LabelAirsAfterSeason": "Diffusion apr\u00e8s la saison :", + "LabelAirsBeforeEpisode": "Diffusion avant l'\u00e9pisode :", + "HeaderExternalIds": "Identifiants externes\u00a0:", + "HeaderDisplaySettings": "Param\u00e8tres d'affichage", + "LabelDisplayOrder": "Ordre d'affichage\u00a0:", + "Display": "Affichage", + "Countries": "Pays", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "\u00c9tiquettes", + "HeaderMetadataSettings": "Param\u00e8tres des m\u00e9tadonn\u00e9es", + "People": "Personnes", + "LabelMetadataDownloadLanguage": "Langue de t\u00e9l\u00e9chargement pr\u00e9f\u00e9r\u00e9e\u00a0:", + "LabelLockItemToPreventChanges": "Verrouiller cet \u00e9l\u00e9ment pour \u00e9viter de futures modifications", + "MessageLeaveEmptyToInherit": "Laisser vide pour h\u00e9riter des param\u00e8tres de l'\u00e9l\u00e9ment parent, ou de la valeur globale par d\u00e9faut.", + "LabelCountry": "Pays\u00a0:", + "LabelDynamicExternalId": "ID {0} :", + "LabelBirthYear": "Ann\u00e9e de naissance :", + "LabelBirthDate": "Date de naissance :", + "LabelDeathDate": "Date de d\u00e9c\u00e8s :", + "LabelEndDate": "Date de fin\u00a0:", + "LabelSeasonNumber": "Num\u00e9ro de saison\u00a0:", + "LabelEpisodeNumber": "Num\u00e9ro d'\u00e9pisode\u00a0:", + "LabelTrackNumber": "Num\u00e9ro de piste\u00a0:", + "LabelNumber": "Num\u00e9ro\u00a0:", + "LabelDiscNumber": "Num\u00e9ro de disque\u00a0:", + "LabelParentNumber": "Num\u00e9ro du parent\u00a0:", + "SortName": "Nom de tri", + "ReleaseDate": "Date de sortie", + "Continuing": "En cours", + "Ended": "Termin\u00e9", + "HeaderEnabledFields": "Activer les champs", + "HeaderEnabledFieldsHelp": "D\u00e9cocher un champ pour le verrouiller et emp\u00eacher ses donn\u00e9es d'\u00eatre modifi\u00e9es.", + "Backdrops": "Arri\u00e8re-plans", + "Images": "Images", + "Runtime": "Dur\u00e9e", + "ProductionLocations": "Sites de production", + "BirthLocation": "Lieu de naissance", + "ParentalRating": "Classification parentale", + "PlayCount": "Nombre de lectures", + "Name": "Nom", + "Overview": "Synopsis", + "LabelType": "Type :", + "LabelPersonRole": "R\u00f4le\u00a0:", + "LabelPersonRoleHelp": "Exemple\u00a0: Chauffeur de camion de cr\u00e8me glac\u00e9e", + "Actor": "Acteur(trice)", + "Composer": "Compositeur(trice)", + "Director": "R\u00e9alisateur(trice)", + "GuestStar": "Guest star", + "Producer": "Producteur(trice)", + "Writer": "Sc\u00e9nariste", + "MessageNoSyncJobsFound": "Aucun t\u00e9l\u00e9chargement trouv\u00e9. Vous pouvez cr\u00e9er des t\u00e2ches de t\u00e9l\u00e9chargement gr\u00e2ce aux boutons T\u00e9l\u00e9charger pr\u00e9sents dans l'application.", + "MessageNoDownloadsFound": "Aucun t\u00e9l\u00e9chargement hors ligne. T\u00e9l\u00e9chargez votre contenu multim\u00e9dia pour une utilisation hors ligne en cliquant sur T\u00e9l\u00e9charger dans l'application.", + "InstallingPackage": "Installation de {0}", + "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", + "ValueOneItem": "1 \u00e9l\u00e9ment", + "ValueOneSong": "1 chanson", + "ValueSongCount": "{0} chansons", + "ValueOneMovie": "1 film", + "ValueMovieCount": "{0} films", + "ValueOneSeries": "1 s\u00e9rie", + "ValueSeriesCount": "{0} s\u00e9ries", + "ValueOneEpisode": "1 \u00e9pisode", + "ValueEpisodeCount": "{0} \u00e9pisodes", + "ValueOneGame": "1 jeu", + "ValueGameCount": "{0} jeux", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 vid\u00e9o musicale", + "ValueMusicVideoCount": "{0} vid\u00e9os musicales", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Chansons", + "Books": "Livres", + "HeaderAudioBooks": "Livres audios", + "HeaderIdentifyItemHelp": "Entrez un ou plusieurs crit\u00e8res de recherche. Retirez des crit\u00e8res pour \u00e9largir les r\u00e9sultats de la recherche.", + "PleaseEnterNameOrId": "Veuillez saisir un nom ou un identifiant externe.", + "MessageItemSaved": "\u00c9l\u00e9ment enregistr\u00e9.", + "SearchResults": "R\u00e9sultats de la recherche", + "ServerNameIsRestarting": "Serveur Emby - {0} red\u00e9marre.", + "ServerNameIsShuttingDown": "Serveur Emby - {0} s'arr\u00eate.", + "HeaderDeleteItems": "Supprimer les \u00e9l\u00e9ments", + "ConfirmDeleteItems": "Supprimer ces \u00e9l\u00e9ments les effacera \u00e0 la fois du syst\u00e8me de fichiers et de votre m\u00e9diath\u00e8que. Voulez-vous vraiment continuer ?", + "PleaseRestartServerName": "Veuillez red\u00e9marrer le serveur Emby - {0}.", + "LabelSyncJobName": "Nom de la t\u00e2che de synchronisation :", + "SyncingDots": "Synchronisation...", + "ConvertingDots": "Conversion...", + "LabelQuality": "Qualit\u00e9\u00a0:", + "LabelSyncNoTargetsHelp": "Il semble que vous n'ayez actuellement aucune application qui supporte le t\u00e9l\u00e9chargement hors ligne.", + "DownloadingDots": "T\u00e9l\u00e9chargement...", + "HeaderSyncRequiresSub": "Le t\u00e9l\u00e9chargement n\u00e9cessite un abonnement Emby Premiere.", + "LearnMore": "En savoir plus", + "LabelProfile": "Profil :", + "LabelBitrateMbps": "D\u00e9bit (Mbps) :", + "ConvertUnwatchedVideosOnly": "Convertir les vid\u00e9os non lues uniquement", + "SyncUnwatchedVideosOnly": "T\u00e9l\u00e9charger seulement les vid\u00e9os non lues", + "ConvertUnwatchedVideosOnlyHelp": "Seulement les vid\u00e9os non lues seront converties", + "SyncUnwatchedVideosOnlyHelp": "Seule les vid\u00e9os non lues seront t\u00e9l\u00e9charg\u00e9es et les vid\u00e9os seront supprim\u00e9es de l'appareil au fur et \u00e0 mesure que vous les regardez.", + "AutomaticallySyncNewContent": "T\u00e9l\u00e9charger automatiquement le nouveau contenu", + "AutomaticallySyncNewContentHelp": "Le nouveau contenu ajout\u00e9 \u00e0 ce dossier sera automatiquement transf\u00e9r\u00e9 vers l'appareil.", + "AutomaticallyConvertNewContent": "Convertir automatiquement les nouveaux contenus", + "AutomaticallyConvertNewContentHelp": "Les nouveaux contenus seront automatiquement convertis", + "LabelItemLimit": "\u00c9l\u00e9ments maximum :", + "ConvertItemLimitHelp": "Optionnel. D\u00e9finir une limite de nombre d'\u00e9l\u00e9ments \u00e0 convertir.", + "DownloadItemLimitHelp": "Optionnel. D\u00e9finir une limite de nombre d'\u00e9l\u00e9ments \u00e0 t\u00e9l\u00e9charger.", + "PleaseSelectDeviceToSyncTo": "Veuillez s\u00e9lectionner l'appareil auquel le t\u00e9l\u00e9chargement doit \u00eatre envoy\u00e9.", + "Screenshots": "Captures d'\u00e9cran", + "MoveRight": "D\u00e9placer \u00e0 droite", + "MoveLeft": "D\u00e9placer \u00e0 gauche", + "ConfirmDeleteImage": "Supprimer l'image ?", + "HeaderEditImages": "Modifier les images", + "Settings": "Param\u00e8tres", + "ShowIndicatorsFor": "Montrer les indicateurs pour\u00a0:", + "NewEpisodes": "Nouveaux \u00e9pisodes", + "Episodes": "\u00c9pisodes", + "HDPrograms": "Programmes HD", + "Programs": "Programmes", + "LiveBroadcasts": "Diffusions en direct", + "Premieres": "In\u00e9dits", + "RepeatEpisodes": "Rediffusions", + "DvrSubscriptionRequired": "Le magn\u00e9toscope Emby n\u00e9cessite un abonnement 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": "Supprimer le m\u00e9dia", + "SeriesSettings": "Param\u00e8tres 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\u00a0:", + "ChannelNameOnly": "Seulement la cha\u00eene {0}", + "Anytime": "N'importe quand", + "AnyLanguage": "N'importe quel langage", + "AroundTime": "Aux environs de {0}", + "All": "Tout", + "AllChannels": "Toutes les cha\u00eenes", + "LabelRecord": "Enregistrer\u00a0:", + "NewEpisodesOnly": "Uniquement les nouveaux \u00e9pisodes", + "AllEpisodes": "Tous les \u00e9pisodes", + "LabelStartWhenPossible": "Commencer si possible\u00a0:", + "LabelStopWhenPossible": "Arr\u00eater si possible\u00a0:", + "MinutesBefore": "minutes avant", + "MinutesAfter": "minutes apr\u00e8s", + "SkipEpisodesAlreadyInMyLibrary": "Ne pas enregistrer les \u00e9pisodes d\u00e9j\u00e0 pr\u00e9sents dans ma m\u00e9diath\u00e8que", + "SkipEpisodesAlreadyInMyLibraryHelp": "Les \u00e9pisodes seront compar\u00e9s en utilisant le num\u00e9ro de saison et le num\u00e9ro d'\u00e9pisode, s'ils sont disponibles.", + "LabelKeepUpTo": "Garder jusqu'\u00e0\u00a0:", + "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:": "Garder\u00a0:", + "UntilIDelete": "Jusqu'\u00e0 ce que je le supprime", + "UntilSpaceNeeded": "Jusqu'\u00e0 ce que l'espace disque soit n\u00e9cessaire", + "Categories": "Cat\u00e9gories", + "Sports": "Sports", + "News": "Actualit\u00e9s", + "Movies": "Films", + "Kids": "Jeunesse", + "EnableColorCodedBackgrounds": "Activer les fonds avec code couleur", + "SortChannelsBy": "Trier les cha\u00eenes par\u00a0:", + "RecentlyWatched": "Lu r\u00e9cemment", + "ChannelNumber": "Num\u00e9ro de cha\u00eene", + "HeaderBenefitsEmbyPremiere": "Les avantages d'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\u00a0?", + "IHaveEmbyPremiere": "J'ai Emby Premiere", + "IPurchasedThisApp": "J'ai achet\u00e9 cette application", + "ButtonRestorePreviousPurchase": "Restaurer l'achat", + "ButtonUnlockWithPurchase": "D\u00e9verrouillez avec un achat", + "ButtonUnlockPrice": "D\u00e9verrouiller {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere {0} mensuel", + "HeaderAlreadyPaid": "Vous avez d\u00e9j\u00e0 pay\u00e9 ?", + "ButtonPlayOneMinute": "Lire une minute", + "PlaceFavoriteChannelsAtBeginning": "Mettre vos cha\u00eenes favorites au d\u00e9but", + "HeaderUnlockFeature": "D\u00e9verrouiller la fonctionnalit\u00e9", + "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 apporte l'exp\u00e9rience du cin\u00e9ma directement dans votre salon gr\u00e2ce \u00e0 la possibilit\u00e9 de lire des bandes-annonces et des introductions personnalis\u00e9es avant le film principal.", + "HeaderPlayMyMedia": "Lire mon m\u00e9dia", + "HeaderDiscoverEmbyPremiere": "D\u00e9couvrez Emby Premiere", + "Items": "\u00c9l\u00e9ments", + "OneChannel": "Une cha\u00eene", + "ConfirmRemoveDownload": "Supprimer le t\u00e9l\u00e9chargement ?", + "RemoveDownload": "Supprimer le t\u00e9l\u00e9chargement", + "KeepDownload": "Garder le t\u00e9l\u00e9chargement", + "AddedOnValue": "Ajout\u00e9 le {0}", + "RemovingFromDevice": "Suppression de l'appareil", + "KeepOnDevice": "Garder sur l'appareil", + "CancelDownload": "Annuler le t\u00e9l\u00e9chargement", + "SyncJobItemStatusReadyToTransfer": "Pr\u00eat pour le transfert", + "SyncJobItemStatusSyncedMarkForRemoval": "Suppression de l'appareil", + "SyncJobItemStatusQueued": "Mis en file d'attente", + "SyncJobItemStatusConverting": "Conversion en cours", + "SyncJobItemStatusTransferring": "Transfert en cours", + "SyncJobItemStatusSynced": "T\u00e9l\u00e9charg\u00e9", + "SyncJobItemStatusFailed": "\u00c9chou\u00e9", + "SyncJobItemStatusRemovedFromDevice": "Supprim\u00e9 de l'appareil", + "SyncJobItemStatusCancelled": "Annul\u00e9", + "Retry": "R\u00e9essayer", + "HeaderMyDevice": "Cet appareil", + "Continue": "Continuer", + "ContinueInSecondsValue": "Continuer dans {0} secondes.", + "HeaderRemoteControl": "Contr\u00f4le \u00e0 distance", + "Disconnect": "D\u00e9connecter", + "EnableDisplayMirroring": "Activer le partage d'\u00e9cran", + "HeaderPlayOn": "Jouer sur", + "Quality": "Qualit\u00e9", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "Pour restaurer votre achat pr\u00e9c\u00e9dent, assurez-vous de vous connecter \u00e0 l'appareil avec le m\u00eame compte Google (ou Amazon) qui a effectu\u00e9 l'achat. Assurez-vous que la boutique d'applications est activ\u00e9e et n'est restreinte par aucun contr\u00f4le parental, et assurez-vous d'avoir une connexion Internet fonctionnelle. Vous n'aurez \u00e0 le faire qu'une seule fois, pour restaurer votre achat pr\u00e9c\u00e9dent.", + "AspectRatio": "Ratio d'aspect original", + "Original": "Original", + "Fill": "Remplir", + "BestFit": "Ajust\u00e9", + "MessageNoServersAvailableToConnect": "Connexion impossible, aucun serveur disponible. Si vous avez \u00e9t\u00e9 invit\u00e9 \u00e0 partager un serveur, veuillez accepter ci-dessous ou en cliquant sur le lien dans le courriel.", + "MessagePlayAccessRestricted": "La lecture de ce contenu est actuellement restreinte. Contactez l'administrateur de votre serveur Emby pour plus d'informations.", + "Accept": "Accepter", + "Reject": "Refuser", + "Connect": "Se connecter", + "HeaderMyMedia": "Mes M\u00e9dias", + "HeaderMyMediaSmall": "Mes m\u00e9dias (Petit)", + "LatestFromLibrary": "{0}, ajouts r\u00e9cents", + "ContinueWatching": "Continuez \u00e0 regarder", + "HeaderLatestChannelMedia": "Derniers \u00e9l\u00e9ments de la cha\u00eene", + "HeaderContinueWatching": "Reprendre", + "HeaderContinueListening": "Reprendre l'\u00e9coute", + "HeaderActiveRecordings": "Enregistrements actifs", + "HeaderLatestRecordings": "Derniers enregistrements", + "LabelSyncTo": "Synchroniser avec :", + "LabelConvertTo": "Convertir en :", + "Next": "Prochain", + "LabelSource": "Source:", + "LabelVersion": "Version :", + "AllLanguages": "Tous les langages", + "Previous": "Pr\u00e9c\u00e9dent", + "HeaderNextUp": "\u00c0 suivre", + "HeaderLatestFrom": "{0}, ajouts r\u00e9cents", + "LabelHomeScreenSectionValue": "Section {0} de l'accueil\u00a0:", + "SettingsSaved": "Param\u00e8tres enregistr\u00e9s.", + "None": "Aucun", + "More": "Plus", + "Up": "Haut", + "Down": "Bas", + "Home": "Accueil", + "Favorites": "Favoris", + "HeaderHomeScreen": "\u00c9cran d'accueil", + "HeaderLatestChannelItems": "Derniers \u00e9l\u00e9ments de la cha\u00eene", + "HeaderLibraryOrder": "Ordre de la m\u00e9diath\u00e8que", + "HideWatchedContentFromLatestMedia": "Masquer le contenu d\u00e9j\u00e0 vu dans les derniers m\u00e9dias", + "HeaderOnNow": "En ce moment", + "HeaderPlaybackError": "Erreur de lecture", + "PlaybackErrorNotAllowed": "Vous n'\u00eates pas autoris\u00e9 \u00e0 lire ce contenu. Veuillez contacter votre administrateur syst\u00e8me pour plus de d\u00e9tails.", + "PlaybackErrorNoCompatibleStream": "Aucun flux compatible n'est actuellement disponible. Veuillez r\u00e9essayer plus tard ou contactez votre administrateur syst\u00e8me pour plus de d\u00e9tails.", + "PlaybackErrorPlaceHolder": "Veuillez ins\u00e9rer le disque pour lire cette vid\u00e9o.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Collections Favorites", + "HeaderFavoritePlaylists": "Listes de lecture favorites", + "Collections": "Collections", + "LabelSelectFolderGroups": "Grouper automatiquement le contenu des dossiers suivants dans des cat\u00e9gories telles que Films, Musique et TV\u00a0:", + "LabelSelectFolderGroupsHelp": "Les dossiers qui ne sont pas coch\u00e9s seront affich\u00e9s tels quels, avec leur propre vue.", + "Folders": "Dossiers", + "DisplayInOtherHomeScreenSections": "Afficher dans les sections de l\u2019\u00e9cran d\u2019accueil comme Ajouts r\u00e9cents et Reprendre", + "DisplayInMyMedia": "Afficher sur l\u2019\u00e9cran d\u2019accueil", + "Shows": "\u00c9missions", + "HeaderLibraryFolders": "Dossiers de la m\u00e9diath\u00e8que", + "HeaderTermsOfPurchase": "Conditions d'achat", + "PrivacyPolicy": "Politique de confidentialit\u00e9", + "TermsOfUse": "Conditions d'utilisation", + "RepeatMode": "Mode de r\u00e9p\u00e9tition", + "RepeatOne": "R\u00e9p\u00e9ter un m\u00e9dia", + "RepeatAll": "Tout r\u00e9p\u00e9ter", + "LabelDefaultScreen": "\u00c9cran par d\u00e9faut", + "ConfirmEndPlayerSession": "Voulez-vous arr\u00eater Emby sur {0} ?", + "Yes": "Oui", + "No": "Non", + "LiveTV": "TV en direct", + "Schedule": "Planning", + "Recordings": "Enregistrements", + "MarkWatched": "Marquer comme lu", + "ScanForNewAndUpdatedFiles": "Actualiser pour d\u00e9tecter les nouveaux fichiers et les modifications", + "DirectStreamHelp1": "Le m\u00e9dia est compatible avec l'appareil en ce qui concerne la r\u00e9solution et le type de m\u00e9dia (H.264, AC3 etc), mais se trouve dans un conteneur de fichiers incompatible (.mkv, .avi, .wmv etc). La vid\u00e9o sera rempaquet\u00e9e \u00e0 la vol\u00e9e avant d'\u00eatre diffus\u00e9e \u00e0 l'appareil.", + "DirectStreamHelp2": "Le streaming en direct d'un fichier utilise tr\u00e8s peu de puissance de traitement sans perte de qualit\u00e9 vid\u00e9o.", + "MediaIsBeingConverted": "Le m\u00e9dia est converti en un format compatible avec l'appareil qui lit le m\u00e9dia.", + "StatsForNerds": "Statistiques pour les geeks", + "LabelReasonForTranscoding": "Raison du transcodage\u00a0:", + "DirectPlaying": "Lecture directe", + "DirectStreaming": "Streaming direct", + "Transcoding": "Transcodage", + "ContainerBitrateExceedsLimit": "Le d\u00e9bit du m\u00e9dia d\u00e9passe la limite.", + "VideoCodecNotSupported": "Codec vid\u00e9o non support\u00e9", + "AudioCodecNotSupported": "Codec audio non support\u00e9", + "SubtitleCodecNotSupported": "Format des sous-titres non pris en charge", + "DirectPlayError": "Erreur de lecture directe", + "ContainerNotSupported": "Conteneur non pris en charge", + "VideoLevelNotSupported": "Niveau vid\u00e9o non pris en charge", + "AudioBitrateNotSupported": "D\u00e9bit audio non pris en charge", + "AudioChannelsNotSupported": "Canaux audio non prises en charge", + "VideoResolutionNotSupported": "R\u00e9solution vid\u00e9o non prise en charge", + "AudioProfileNotSupported": "Profil audio non pris en charge", + "AudioSampleRateNotSupported": "Taux d'\u00e9chantillonnage audio non pris en charge", + "AnamorphicVideoNotSupported": "Vid\u00e9o anamorphique non prise en charge", + "InterlacedVideoNotSupported": "Vid\u00e9o entrelac\u00e9e non prise en charge", + "SecondaryAudioNotSupported": "Commutation de piste audio non prise en charge", + "ErrorRemovingEmbyConnectAccount": "Une erreur est survenue pendant la suppression du compte Emby Connect. Veuillez vous assurer que vous avez une connexion internet active puis r\u00e9essayez.", + "HeaderEmbyAccountRemoved": "Compte Emby supprim\u00e9", + "MessageEmbyAccontRemoved": "Le compte Emby a \u00e9t\u00e9 supprim\u00e9 pour cet utilisateur.", + "HeaderInvitationSent": "Invitation envoy\u00e9e", + "MessageInvitationSentToUser": "Un courriel a \u00e9t\u00e9 envoy\u00e9 \u00e0 {0} avec votre invitation de partage.", + "MessageInvitationSentToNewUser": "Un courriel a \u00e9t\u00e9 envoy\u00e9 \u00e0 {0}, les invitant \u00e0 s'inscrire \u00e0 Emby.", + "GuestUserNotFound": "Utilisateur non trouv\u00e9. Veuillez v\u00e9rifier que le nom est correct et essayez \u00e0 nouveau, ou essayez de renseigner l'adresse courriel.", + "ErrorReachingEmbyConnect": "Une erreur est survenue pendant la connexion au serveur Emby Connect. Veuillez vous assurer que vous avez une connexion internet active puis r\u00e9essayez.", + "ErrorAddingEmbyConnectAccount1": "Une erreur est survenue lors de l'ajout du compte Emby Connect. Avez-vous cr\u00e9\u00e9 un compte Emby\u00a0? Inscrivez-vous sur {0}.", + "ErrorAddingEmbyConnectAccount2": "Si le probl\u00e8me persiste, veuillez envoyer un courriel \u00e0 {0} avec l'adresse utilis\u00e9e lors de la cr\u00e9ation de votre compte Emby.", + "ErrorAddingGuestAccount1": "Une erreur est survenue lors de l'ajout du compte Emby Connect. Vos invit\u00e9s ont-ils cr\u00e9\u00e9 un compte Emby ? Ils peuvent s'inscrire sur {0}.", + "ErrorAddingGuestAccount2": "Si le probl\u00e8me persiste, veuillez envoyer un courriel \u00e0 {0} en pr\u00e9cisant votre adresse courriel ainsi que la leur.", + "MessageEmbyAccountAdded": "Le compte Emby a \u00e9t\u00e9 ajout\u00e9 \u00e0 cet utilisateur.", + "MessagePendingEmbyAccountAdded": "Le compte Emby a \u00e9t\u00e9 ajout\u00e9 \u00e0 cet utilisateur. Un courriel sera envoy\u00e9 au propri\u00e9taire du compte. Cette invitation devra \u00eatre confirm\u00e9e en cliquant sur un lien pr\u00e9sent dans le courriel.", + "HeaderEmbyAccountAdded": "Compte Emby ajout\u00e9", + "LabelSubtitlePlaybackMode": "Mode des sous-titres :", + "ErrorDeletingItem": "Une erreur s'est produite lors de la suppression de l'\u00e9l\u00e9ment du serveur Emby. V\u00e9rifiez que le serveur Emby a un acc\u00e8s en \u00e9criture au dossier multim\u00e9dia et r\u00e9essayez.", + "NoSubtitles": "Pas de sous-titres", + "Default": "Par d\u00e9faut", + "Absolute": "Absolu", + "Smart": "Intelligent", + "Small": "Petit", + "Smaller": "Plus petit", + "Medium": "Moyen", + "Large": "Grand", + "ExtraLarge": "Tr\u00e8s grand", + "OnlyForcedSubtitles": "Seulement les sous-titres forc\u00e9s", + "AlwaysPlaySubtitles": "Toujours lancer les sous-titres", + "DefaultSubtitlesHelp": "Les sous-titres seront charg\u00e9s selon les marqueurs par d\u00e9faut et forc\u00e9 dans les m\u00e9tadonn\u00e9es int\u00e9gr\u00e9es. Les langues pr\u00e9f\u00e9r\u00e9es seront utilis\u00e9es quand plusieurs options seront disponibles.", + "SmartSubtitlesHelp": "Les sous-titres correspondant \u00e0 la langue pr\u00e9f\u00e9r\u00e9e seront charg\u00e9s lorsque l'audio est dans une langue \u00e9trang\u00e8re.", + "HeaderSubtitleSettings": "Param\u00e8tres des sous-titres", + "HeaderSubtitleAppearance": "Apparence des sous-titres", + "OnlyForcedSubtitlesHelp": "Seuls les sous-titres marqu\u00e9s comme forc\u00e9s seront charg\u00e9s.", + "AlwaysPlaySubtitlesHelp": "Les sous-titres correspondant \u00e0 la pr\u00e9f\u00e9rence linguistique seront charg\u00e9s ind\u00e9pendamment de la langue de l'audio.", + "NoSubtitlesHelp": "Les sous-titres ne seront pas charg\u00e9s par d\u00e9faut. Ils peuvent toujours \u00eatre activ\u00e9s manuellement pendant la lecture.", + "LabelPreferredSubtitleLanguage": "Langue de sous-titrage pr\u00e9f\u00e9r\u00e9e:", + "LabelTextSize": "Taille du texte\u00a0:", + "TheseSettingsAffectSubtitlesOnThisDevice": "Ces param\u00e8tres affectent les sous-titres de cet appareil", + "LabelDropShadow": "Ombre port\u00e9e\u00a0:", + "LabelTextBackgroundColor": "Couleur de fond du texte\u00a0:", + "LabelWindowBackgroundColor": "Couleur de fond du texte\u00a0:", + "LabelFont": "Police\u00a0:", + "LabelTextColor": "Couleur du texte\u00a0:", + "Raised": "Augmenter", + "Depressed": "Diminuer", + "Uniform": "Uniforme", + "DropShadow": "Ombre port\u00e9e", + "SmallCaps": "Petites majuscules", + "SubtitleAppearanceSettingsDisclaimer": "Ces param\u00e8tres ne s'appliqueront pas aux sous-titres graphiques (PGS, DVD etc) ou aux sous-titres qui ont leurs propres styles incorpor\u00e9s (ASS\/SSA).", + "LabelBurnSubtitles": "Graver les sous-titres\u00a0:", + "OnlyImageFormats": "Seulement les formats image (VOBSUB, PGS, SUB\/IDX etc)", + "Normal": "Normal", + "BurnSubtitlesHelp": "D\u00e9termine si le serveur doit graver les sous-titres lors de la conversion vid\u00e9o en fonction du format des sous-titres. \u00c9viter la gravure des sous-titres am\u00e9liorera les performances du serveur. S\u00e9lectionnez Auto pour graver les formats bas\u00e9s sur l'image (par exemple, VOBSUB, PGS, SUB\/IDX etc) ainsi que certains sous-titres ASS\/SSA", + "AllComplexFormats": "Tous les formats complexes (ASS, SSA, VOBSUB, PGS, SUB\/IDX etc)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Ces param\u00e8tres s'appliquent \u00e9galement \u00e0 toute lecture Chromecast d\u00e9marr\u00e9e par cet appareil.", + "HeaderWaitingForWifi": "En attente du Wi-Fi", + "WifiRequiredToDownload": "Une connexion Wi-Fi est n\u00e9cessaire pour continuer le t\u00e9l\u00e9chargement.", + "HeaderDownloadSettings": "Param\u00e8tres de t\u00e9l\u00e9chargement", + "Hide": "Cacher", + "HeaderStartNow": "Commencer maintenant", + "HeaderNextVideoPlayingInValue": "Lecture de la prochaine vid\u00e9o dans {0}", + "HeaderNextEpisodePlayingInValue": "Lecture du prochain \u00e9pisode dans {0}", + "HeaderSecondsValue": "{0} secondes", + "AudioBitDepthNotSupported": "Profondeur des \u00e9chantillons de l'audio non prise en charge", + "VideoProfileNotSupported": "Profil vid\u00e9o non pris en charge", + "VideoFramerateNotSupported": "Nombre d'images par seconde de la vid\u00e9o non pris en charge", + "VideoBitDepthNotSupported": "Profondeur des couleurs de la vid\u00e9o non prise en charge", + "RefFramesNotSupported": "Nombre d'images de r\u00e9f\u00e9rence de la vid\u00e9o non pris en charge", + "ErrorConnectServerUnreachable": "Une erreur est survenue pendant l'ex\u00e9cution de l'op\u00e9ration demand\u00e9e. Votre serveur est dans l'incapacit\u00e9 de joindre le serveur d'Emby Connect \u00e0 {0}. Veuillez v\u00e9rifier que votre serveur est bien connect\u00e9 \u00e0 Internet et qu'aucun pare-feu ou autre logiciel de s\u00e9curit\u00e9 ne bloque les communications.", + "StopRecording": "Arr\u00eater l'enregistrement", + "HeaderStopRecording": "Arr\u00eater l'enregistrement", + "ManageRecording": "G\u00e9rer l'enregistrement", + "LabelDropImageHere": "Faites glisser l'image ici, ou cliquez pour parcourir vos fichiers.", + "MessageFileReadError": "Une erreur est survenue lors de la lecture du fichier. Veuillez r\u00e9essayer.", + "Browse": "Parcourir", + "HeaderUploadImage": "Envoyer une image", + "HeaderAddUpdateImage": "Ajouter\/Mettre \u00e0 jour une image", + "LabelImageType": "Type d'image\u00a0:", + "Upload": "Envoyer", + "Primary": "Principal", + "Art": "Art", + "Backdrop": "Arri\u00e8re-plan", + "Banner": "Banni\u00e8re", + "Box": "Bo\u00eetier", + "BoxRear": "Dos de bo\u00eetier", + "Disc": "Disque", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Capture d'\u00e9cran", + "Thumb": "Vignette", + "ValueSeconds": "{0} secondes", + "HeaderAudioSettings": "R\u00e9glages audio", + "LabelAudioLanguagePreference": "Langue audio pr\u00e9f\u00e9r\u00e9e\u00a0:", + "LabelPlayDefaultAudioTrack": "Utiliser le flux audio par d\u00e9faut quelle que soit la langue", + "HeaderVideoQuality": "Qualit\u00e9 vid\u00e9o", + "CinemaModeConfigurationHelp": "Le mode cin\u00e9ma apporte l'exp\u00e9rience du cin\u00e9ma directement dans votre salon gr\u00e2ce \u00e0 la possibilit\u00e9 de lire des bandes-annonces et des introductions personnalis\u00e9es avant le film principal.", + "EnableNextVideoInfoOverlay": "Activer les informations de la vid\u00e9o suivante pendant la lecture", + "EnableNextVideoInfoOverlayHelp": "\u00c0 la fin d'une vid\u00e9o, afficher les informations sur la vid\u00e9o suivante dans la file d'attente.", + "PlayNextEpisodeAutomatically": "Lancer l'\u00e9pisode suivant automatiquement", + "LabelMaxChromecastBitrate": "Qualit\u00e9 maximum pour Chromecast\u00a0:", + "LabelSkipBackLength": "Dur\u00e9e des sauts en arri\u00e8re\u00a0:", + "LabelSkipForwardLength": "Dur\u00e9e des sauts en avant\u00a0:", + "EnableCinemaMode": "Activer le mode cin\u00e9ma", + "LabelInternetQuality": "Qualit\u00e9 d'internet\u00a0:", + "HeaderMusicQuality": "Qualit\u00e9 de la musique\u00a0:", + "LabelHomeNetworkQuality": "Qualit\u00e9 du r\u00e9seau local\u00a0:", + "HeaderLatestMedia": "Derniers m\u00e9dias", + "HeaderRestartingEmbyServer": "Red\u00e9marrage du serveur Emby", + "RestartPleaseWaitMessage": "Veuillez patienter pendant que le serveur Emby s'arr\u00eate et red\u00e9marre. Cela peut prendre une minute ou deux.", + "PlayNext": "Lire le suivant", + "AllowSeasonalThemes": "Autoriser les th\u00e8mes saisonniers automatiques", + "AllowSeasonalThemesHelp": "Des th\u00e8mes saisonniers viendront occasionnellement remplacer votre th\u00e8me r\u00e9gulier.", + "AutoBasedOnLanguageSetting": "Auto (bas\u00e9 sur le r\u00e9glage de la langue)", + "LabelDateTimeLocale": "Date et heure locale\u00a0:", + "DirectorValue": "R\u00e9alisateur: {0}", + "DirectorsValue": "R\u00e9alisateurs: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Liens: {0}", + "TagsValue": "Mots cl\u00e9s: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Vid\u00e9o:", + "LabelSubtitles": "Sous-titres:", + "Off": "D\u00e9sactiv\u00e9s", + "ShowTitle": "Montrer le titre", + "ShowYear": "Voir l'ann\u00e9e", + "Filters": "Filtres", + "Unplayed": "Non lu", + "LabelTVHomeScreen": "\u00c9cran d'accueil du mode TV :", + "Horizontal": "Horizontal", + "Vertical": "Verticale", + "GroupBySeries": "Grouper par s\u00e9ries", + "HeaderVideoType": "Type de vid\u00e9o", + "HeaderSeriesStatus": "Statut de la s\u00e9rie", + "Features": "Longs m\u00e9trages", + "Trailers": "Bandes-annonces", + "Extras": "Extras", + "ThemeSongs": "Chansons th\u00e9matiques", + "ThemeVideos": "Vid\u00e9os th\u00e9matiques", + "HeaderFavoriteMovies": "Films Favoris", + "HeaderFavoriteShows": "S\u00e9ries Favorites", + "HeaderFavoriteEpisodes": "Episodes Favoris", + "HeaderFavoriteVideos": "Vid\u00e9os favoris", + "HeaderFavoriteGames": "Jeux Favoris", + "HeaderFavoriteArtists": "Artistes Favoris", + "HeaderFavoriteAlbums": "Albums Favoris", + "HeaderFavoriteSongs": "Chansons Favorites", + "Ascending": "Croissant", + "Descending": "D\u00e9croissant", + "ColorPrimaries": "Couleurs primaires", + "ColorSpace": "Espace colorim\u00e9trique", + "ColorTransfer": "Transfert de couleur", + "VideoRange": "Gamme vid\u00e9o", + "SeriesDisplayOrderHelp": "Ranger les \u00e9pisodes par date de diffusion, par ordre de DVD ou par num\u00e9ro absolu.", + "PlaybackSettingsIntro": "Pour configurer les r\u00e9glages de lecture par d\u00e9faut, arr\u00eatez la lecture de la vid\u00e9o, puis cliquez sur votre ic\u00f4ne utilisateur situ\u00e9e en haut \u00e0 droite dans l'application.", + "SubtitleSettingsIntro": "Pour configurer l'apparence des sous-titres et la langue par d\u00e9faut, arr\u00eatez la lecture de la vid\u00e9o, puis cliquez sur votre ic\u00f4ne utilisateur situ\u00e9e en haut \u00e0 droite dans l'application." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/gsw.json b/src/bower_components/emby-webcomponents/strings/gsw.json index d883b20325..c30f632bec 100644 --- a/src/bower_components/emby-webcomponents/strings/gsw.json +++ b/src/bower_components/emby-webcomponents/strings/gsw.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Abbreche", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Fortlaufend", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Beendent", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friitig", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artist:", - "LabelArtistsHelp": "Trenn mehreri iisträg dur es ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Date Art:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Land:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Sproch:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Mäntig", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Biispell: Star Wars Sammlig", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Samstig", - "Save": "Speichere", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Dursuechs Internet nach Bilder und Metadate", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Sonntig", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Donnstig", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tsischtig", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Mittwoch", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Abbreche", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Sonntig", + "Monday": "M\u00e4ntig", + "Tuesday": "Tsischtig", + "Wednesday": "Mittwoch", + "Thursday": "Donnstig", + "Friday": "Friitig", + "Saturday": "Samstig", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Speichere", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Dursuechs Internet nach Bilder und Metadate", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Biispell: Star Wars Sammlig", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Sproch:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Date Art:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artist:", + "LabelArtistsHelp": "Trenn mehreri iistr\u00e4g dur es ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Land:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Fortlaufend", + "Ended": "Beendent", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/he.json b/src/bower_components/emby-webcomponents/strings/he.json index cc9687d000..6346a5d44c 100644 --- a/src/bower_components/emby-webcomponents/strings/he.json +++ b/src/bower_components/emby-webcomponents/strings/he.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "שחקן", - "Add": "הוסף", - "AddToCollection": "להוסיף לאוסף", - "AddToPlayQueue": "הוסף לתור הפעלה", - "AddToPlaylist": "הוסף לרשימת ניגון", - "AddedOnValue": "Added {0}", - "Advanced": "מתקדם", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "כל הערוצים", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "כל הפרקים", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "בכל עת", - "AroundTime": "בסביבות {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "כמה שיותר", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "חדש", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "תוכן חדש שנוסף לתיקיה זו יוריד באופן אוטומטי למכשיר.", - "Backdrop": "Backdrop", - "Backdrops": "תפאורות", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "מיקום לידה", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "בטל", - "ButtonGotIt": "הבנתי", - "ButtonOk": "בסדר", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "איתחול", - "ButtonRestorePreviousPurchase": "שחזר רכישה", - "ButtonTryAgain": "נסה שנית", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "ביטול הקלטה", - "CancelSeries": "בטל סדרה", - "Categories": "קטגוריות", - "ChannelNameOnly": "ערוץ {0} בלבד", - "ChannelNumber": "מספר ערוץ", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "מצב קולנוע נותן לך את החוויה הקולנוע אמיתי עם קדימונים מותאמים אישית לפני התכונה.", - "CloudSyncFeatureDescription": "סנכרן את המדיה שלך לענן לצורך גיבוי קל, אחסון בארכיון והמרה.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "מלחין", - "ConfigureDateAdded": "הגדר כיצד תאריך התוספת נקבע בלוח המחוונים של שרת Amby תחת הגדרות ספריה", - "ConfirmDeleteImage": "למחוק את התמונה?", - "ConfirmDeleteItem": "מחיקת פריט זה תמחק אותו הן ממערכת הקבצים והן מספריית המדיה שלך. האם אתה בטוח שברצונך להמשיך?", - "ConfirmDeleteItems": "מחיקת פריטים אלה תמחק אותם הן ממערכת הקבצים והן מספריית המדיה שלך. האם אתה בטוח שברצונך להמשיך?", - "ConfirmDeletion": "אשר מחיקה", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "ממשיך", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "מדינות", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "ימים", - "Default": "Default", - "DefaultErrorMessage": "אירעה שגיאה בעיבוד הבקשה. בבקשה נסה שוב מאוחר יותר.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "מחק", - "DeleteMedia": "מחק מדיה", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "מנהל", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "לא אוהב", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "אל תקליט", - "Down": "Down", - "Download": "הורדה", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "הורדות", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "אמבי DVR דורשת מנוי פעיל של Jellyfin Premiere.", - "Edit": "ערוך", - "EditImages": "ערוך תמונות", - "EditMetadata": "Edit metadata", - "EditSubtitles": "ערוך כתוביות", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "אפשר רקע בצבע מקודד", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "הסתיים", - "EndsAtValue": "מסתיים ב {0}", - "Episodes": "Episodes", - "Error": "שגיאה", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "מועדף", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "תכונה זו דורשת מנוי פעיל של Jellyfin Premiere.", - "Features": "Features", - "File": "קובץ", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "באפשרותך ליהנות מגישה חופשית ליישומי Jellyfin עבור המכשירים שלך.", - "Friday": "שישי", - "GenreValue": "Genre: {0}", - "Genres": "ז'אנרים", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "גרסאות קבוצתיות", - "GuestStar": "כוכב אורח", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "תוכניות HD", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "להוסיף לאוסף", - "HeaderAddToPlaylist": "הוסף לרשימת ניגון", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "קבל Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "היתרונות של אמבי Premiere", - "HeaderCancelRecording": "ביטול הקלטה", - "HeaderCancelSeries": "בטל סדרה", - "HeaderCinemaMode": "מצב קולנוע", - "HeaderCloudSync": "סנכרון ענן", - "HeaderConfirmRecordingCancellation": "אשר ביטול הקלטה", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "המרת הקלטות שלך", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "מחק פריט", - "HeaderDeleteItems": "מחיקת פריטים", - "HeaderDisplaySettings": "הגדרות תצוגה", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "ערוך תמונות", - "HeaderEnabledFields": "שדות זמינים", - "HeaderEnabledFieldsHelp": "בטל את הסימון בשדה כדי לנעול אותו ולמנוע שינוי בנתונים.", - "HeaderExternalIds": "מזהים חיצוניים:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "אפליקציות אמבי בחינם", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "הזן קריטריון חיפוש אחד או יותר. הסר קריטריונים כדי להגדיל את תוצאות החיפוש.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "שמור על הקלטה", - "HeaderKeepSeries": "שמור סדרה", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "למד עוד", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "הגדרות מטא נתונים", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "הקלטה חדשה", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "מדיה לא מקוונת", - "HeaderOfflineDownloadsDescription": "הורד מדיה למכשירים שלך לשימוש לא מקוון בקלות.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "אפשרויות הקלטה", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "תגיד משהו כמו ...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "בחר תאריך", - "HeaderSeriesOptions": "אפשרויות סדרה", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "פרטי אפיזודות מיוחדות", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "נסה הפעלה", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "אתה אמרת...", - "Help": "עזרה", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "איך שילמת?", - "IHaveJellyfinPremiere": "יש לי אמבי Premiere", - "IPurchasedThisApp": "רכשתי את האפליקציה הזו", - "Identify": "לזהות", - "Images": "תמונות", - "ImdbRating": "IMDb rating", - "InstallingPackage": "מתקין {0}", - "InstantMix": "מיקס מיידי", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "פריטים {0}", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "ילדים", - "Label3DFormat": "פורמט תלת-ממדי:", - "LabelAirDays": "ימי אויר:", - "LabelAirTime": "זמן אוויר:", - "LabelAirsAfterSeason": "באוויר אחרי העונה:", - "LabelAirsBeforeEpisode": "באוויר לפני פרק:", - "LabelAirsBeforeSeason": "באוויר לפני העונה:", - "LabelAlbum": "אלבום:", - "LabelAlbumArtists": "אלבום אומנים:", - "LabelArtists": "אומנים:", - "LabelArtistsHelp": "הפרד מרובים באמצעות;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "תאריך לידה:", - "LabelBirthYear": "שנת לידה:", - "LabelBitrateMbps": "קצב סיביות (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "ערוצים:", - "LabelCollection": "אוספים:", - "LabelCommunityRating": "דירוג הקהילה:", - "LabelContentType": "סוג התוכן", - "LabelConvertTo": "Convert to:", - "LabelCountry": "מדינה:", - "LabelCriticRating": "דירוג ביקורת:", - "LabelCustomRating": "דירוג מותאם אישית:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "תאריך הוסף:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "תאריך המוות:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "מספר דיסק:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "סדר תצוגה:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} תעודת זהות:", - "LabelEmailAddress": "כתובת דוא\"ל:", - "LabelEndDate": "תאריך סיום:", - "LabelEpisodeNumber": "מספר פרק:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "מגבלת פריט:", - "LabelKeep:": "שמור:", - "LabelKeepUpTo": "שמור עד ל:", - "LabelLanguage": "שפה:", - "LabelLockItemToPreventChanges": "נעל פריט זה כדי למנוע שינויים עתידיים", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "שפת הורדה מועדפת:", - "LabelName": "שם:", - "LabelNumber": "מספר:", - "LabelOriginalAspectRatio": "יחס גובה-רוחב מקורי:", - "LabelOriginalTitle": "כותרת מקורית:", - "LabelOverview": "סקירה כללית:", - "LabelParentNumber": "מספר אב:", - "LabelParentalRating": "דירוג ההורים:", - "LabelPath": "נתיב:", - "LabelPersonRole": "תפקיד:", - "LabelPersonRoleHelp": "דוגמה: נהג משאית גלידה", - "LabelPlaceOfBirth": "מקום לידה:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "רשימת ניגון:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "פרופיל:", - "LabelQuality": "איכות:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "הקלטה:", - "LabelRefreshMode": "מצב רענון:", - "LabelReleaseDate": "תאריך הוצאה:", - "LabelRuntimeMinutes": "זמן ריצה (דקות):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "מספר עונה:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "סקירה קצרה:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "מיין כותרת:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "התחל ברגע שניתן:", - "LabelStatus": "סטטוס:", - "LabelStopWhenPossible": "הפסק ברגע שאפשר", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "סנכרן את שם העבודה:", - "LabelSyncNoTargetsHelp": "נראה שאין לך כרגע אפליקציות התומכות בהורדה במצב לא מקוון.", - "LabelSyncTo": "סנכרן ל:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "שורת תיוג:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "כותרת:", - "LabelTrackNumber": "קטע מספר:", - "LabelType": "סוג:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "אתר:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "שנה:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "למד עוד", - "Like": "אוהב", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "שידור חי", - "LiveBroadcasts": "שידורים חיים", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "סמן נוגן", - "MarkUnplayed": "סמן לא נוגן", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "האם אתה בטוח שברצונך למחוק קובץ כתובית זה?", - "MessageConfirmRecordingCancellation": "האם אתה בטוח שברצונך לבטל הקלטה זו?", - "MessageDownloadQueued": "הורד תור", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "אם מנעת גישה קולית לאפליקציה שתצטרך להגדיר מחדש לפני שתנסה שוב.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "הפריט נשמר.", - "MessageItemsAdded": "פריטים נוספו.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "השאר ריק כדי לרשת את ההגדרות מפריט אב, או את ערך ברירת המחדל הגלובלי.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "אם יש לך מנוי פעיל של Jellyfin Premiere, ודא שהגדרת את Jellyfin Premiere במרכז השליטה של ​​אמבי שרת, שבו באפשרותך לגשת על-ידי לחיצה על Jellyfin Premiere בתפריט הראשי.", - "MessageUnlockAppWithPurchaseOrSupporter": "נעילת תכונה זו עם רכישה חד פעמית קטנה, או עם מנוי פעיל Premiere אמבי.", - "MessageUnlockAppWithSupporter": "ביטול נעילה של תכונה זו עם מנוי פעיל של Jellyfin Premiere.", - "MessageWeDidntRecognizeCommand": "אנחנו מצטערים, לא זיהינו את הפקודה הזאת.", - "MinutesAfter": "דקות אחרי", - "MinutesBefore": "דקות לפני", - "Mobile": "Mobile / Tablet", - "Monday": "שני", - "More": "More", - "MoveLeft": "זוז שמאלה", - "MoveRight": "זוז ימינה", - "Movies": "סרטים", - "MySubtitles": "הכתוביות שלי", - "Name": "שם", - "NewCollection": "אוספים חדשים", - "NewCollectionHelp": "אוספים מאפשרים לך ליצור קיבוצים מותאמים אישית של סרטים ותוכן ספריה אחר.", - "NewCollectionNameExample": "לדוגמא :אוסף מלחמת הכוכבים", - "NewEpisodes": "פרקים חדשים", - "NewEpisodesOnly": "פרקים חדשים בלבד", - "News": "חדשות", - "Next": "Next", - "No": "No", - "NoItemsFound": "לא נמצאו פריטים", - "NoSubtitleSearchResultsFound": "לא נמצאו תוצאות.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "פתח", - "OptionNew": "חדש...", - "Original": "Original", - "OriginalAirDateValue": "תאריך אוויר מקורי: {0}", - "Overview": "סקירה כללית", - "PackageInstallCancelled": "{0} ההתקנה בוטלה.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "ההתקנה {0} נכשלה.", - "ParentalRating": "דירוג ההורים", - "People": "אנשים", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "נגן", - "PlayAllFromHere": "נגן הכל מכאן", - "PlayCount": "Play count", - "PlayFromBeginning": "נגן מהתחלה", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "הזן שם או מזהה חיצוני.", - "PleaseRestartServerName": "אנא הפעל מחדש את שרת Jellyfin - {0}.", - "PleaseSelectDeviceToSyncTo": "בחר מכשיר להורדה אליו.", - "PleaseSelectTwoItems": "בחר לפחות שני פריטים.", - "Premiere": "הקרנת בכורה", - "Premieres": "בכורות", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "במאי", - "ProductionLocations": "מיקומי ייצור", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "להמיר באופן אוטומטי הקלטות בפורמט זורם ידידותי עם אמבי Premiere. הקלטות יומרו על לטוס ל MP4 או MKV, בהתבסס על הגדרות שרת אמבי.", - "Quality": "Quality", - "QueueAllFromHere": "הוסף הכל מכאן לתור", - "Raised": "Raised", - "RecentlyWatched": "נצפה לאחרונה", - "Record": "הקלט", - "RecordSeries": "הקלט סדרה", - "RecordingCancelled": "בטל הקלטה", - "RecordingScheduled": "ההקלטה מתוזמנת.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "רענון", - "RefreshDialogHelp": "המטא נתונים מתרעננים על סמך הגדרות ושירותי אינטרנט שמופעלים בלוח המחוונים של מרכז אמבי.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "רענן תור.", - "Reject": "Reject", - "ReleaseDate": "תאריך שיחרור", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "הסר מאוספים", - "RemoveFromPlaylist": "הסר מרשימת הניגון", - "RemovingFromDevice": "Removing from device", - "Repeat": "חזור", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "חזור על פרקים", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "החלף את כל המטא נתונים", - "ReplaceExistingImages": "החלף תמונות קיימות", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "המשך מ {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "זמן ריצה", - "Saturday": "שבת", - "Save": "שמור", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "צילומי מסך", - "Search": "חיפוש", - "SearchForCollectionInternetMetadata": "חפש באינרנט אחרי מידע ותמונות", - "SearchForMissingMetadata": "חפש מטא נתונים חסרים", - "SearchForSubtitles": "חיפוש של כתוביות", - "SearchResults": "תוצאות חיפוש", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "בטל סדרות", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "הקלטת סדרה מתוזמנת.", - "SeriesSettings": "הגדרות סדרה", - "SeriesYearToPresent": "{0} - היום", - "ServerNameIsRestarting": "שרת Jellyfin - {0} מופעל מחדש.", - "ServerNameIsShuttingDown": "שרת Jellyfin - {0} נכבה.", - "ServerUpdateNeeded": "שרת אמבי זה צריך להיות מעודכן. כדי להוריד את הגרסה העדכנית ביותר, בקר בכתובת {0}", - "Settings": "הגדרות", - "SettingsSaved": "Settings saved.", - "Share": "שיתוף", - "ShowIndicatorsFor": "הצג מחוונים עבור:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "ערבב", - "SkipEpisodesAlreadyInMyLibrary": "אל תקליטו פרקים שכבר נמצאים בספרייה שלי", - "SkipEpisodesAlreadyInMyLibraryHelp": "פרקים יושוו באמצעות העונה ואת הפרק פרק, כאשר זמין.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "מיין ערוצים לפי:", - "SortName": "מיין לפי שם", - "Sports": "ספורט", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "אולפני", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "כתוביות", - "Suggestions": "Suggestions", - "Sunday": "ראשון", - "Sync": "סנכרן", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "רק סרטונים שלא הורדו יורדו, וסרטונים יוסרו מהמכשיר כפי שהם צפו.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "תגים", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "אנא ליהנות דקה אחת של השמעה. תודה שניסית את אמבי.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "חמישי", - "TrackCount": "שירים {0}", - "Trailer": "קטעי סרט", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "נסה בחירה מרובה", - "TryMultiSelectMessage": "כדי לערוך פריטי מדיה מרובים, פשוט לחץ לחיצה ארוכה על כל פוסטר ובחר את הפריטים שברצונך לנהל. נסה זאת!", - "Tuesday": "שלישי", - "Uniform": "Uniform", - "UnlockGuide": "נעילת מדריך", - "Unplayed": "Unplayed", - "Unrated": "אין דירוג", - "UntilIDelete": "עד שאמחק", - "UntilSpaceNeeded": "עד הצורך במרחב", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} אלבומים", - "ValueDiscNumber": "דיסק {0}", - "ValueEpisodeCount": "{0} פרקים", - "ValueGameCount": "{0} משחקים", - "ValueMinutes": "{0} דקות", - "ValueMovieCount": "{0} סרטים", - "ValueMusicVideoCount": "{0} וידאו קליפים", - "ValueOneAlbum": "אלבום 1", - "ValueOneEpisode": "פרק 1", - "ValueOneGame": "משחק 1", - "ValueOneItem": "פריט 1", - "ValueOneMovie": "סרט 1", - "ValueOneMusicVideo": "וידאו קליפ 1", - "ValueOneSeries": "1 סדרה", - "ValueOneSong": "שיר 1", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} סדרות", - "ValueSongCount": "{0} שירים", - "ValueSpecialEpisodeName": "מיוחד- {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "צפה באלבום", - "ViewArtist": "צפה באמן", - "VoiceInput": "קלט קולי", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "רביעי", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "כותב", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "\u05e0\u05e2\u05d9\u05dc\u05ea \u05ea\u05db\u05d5\u05e0\u05d4 \u05d6\u05d5 \u05e2\u05dd \u05e8\u05db\u05d9\u05e9\u05d4 \u05d7\u05d3 \u05e4\u05e2\u05de\u05d9\u05ea \u05e7\u05d8\u05e0\u05d4, \u05d0\u05d5 \u05e2\u05dd \u05de\u05e0\u05d5\u05d9 \u05e4\u05e2\u05d9\u05dc Premiere \u05d0\u05de\u05d1\u05d9.", + "MessageUnlockAppWithSupporter": "\u05d1\u05d9\u05d8\u05d5\u05dc \u05e0\u05e2\u05d9\u05dc\u05d4 \u05e9\u05dc \u05ea\u05db\u05d5\u05e0\u05d4 \u05d6\u05d5 \u05e2\u05dd \u05de\u05e0\u05d5\u05d9 \u05e4\u05e2\u05d9\u05dc \u05e9\u05dc Emby Premiere.", + "MessageToValidateSupporter": "\u05d0\u05dd \u05d9\u05e9 \u05dc\u05da \u05de\u05e0\u05d5\u05d9 \u05e4\u05e2\u05d9\u05dc \u05e9\u05dc Emby Premiere, \u05d5\u05d3\u05d0 \u05e9\u05d4\u05d2\u05d3\u05e8\u05ea \u05d0\u05ea Emby Premiere \u05d1\u05de\u05e8\u05db\u05d6 \u05d4\u05e9\u05dc\u05d9\u05d8\u05d4 \u05e9\u05dc \u200b\u200b\u05d0\u05de\u05d1\u05d9 \u05e9\u05e8\u05ea, \u05e9\u05d1\u05d5 \u05d1\u05d0\u05e4\u05e9\u05e8\u05d5\u05ea\u05da \u05dc\u05d2\u05e9\u05ea \u05e2\u05dc-\u05d9\u05d3\u05d9 \u05dc\u05d7\u05d9\u05e6\u05d4 \u05e2\u05dc Emby Premiere \u05d1\u05ea\u05e4\u05e8\u05d9\u05d8 \u05d4\u05e8\u05d0\u05e9\u05d9.", + "ValueSpecialEpisodeName": "\u05de\u05d9\u05d5\u05d7\u05d3- {0}", + "Share": "\u05e9\u05d9\u05ea\u05d5\u05e3", + "Add": "\u05d4\u05d5\u05e1\u05e3", + "ServerUpdateNeeded": "\u05e9\u05e8\u05ea \u05d0\u05de\u05d1\u05d9 \u05d6\u05d4 \u05e6\u05e8\u05d9\u05da \u05dc\u05d4\u05d9\u05d5\u05ea \u05de\u05e2\u05d5\u05d3\u05db\u05df. \u05db\u05d3\u05d9 \u05dc\u05d4\u05d5\u05e8\u05d9\u05d3 \u05d0\u05ea \u05d4\u05d2\u05e8\u05e1\u05d4 \u05d4\u05e2\u05d3\u05db\u05e0\u05d9\u05ea \u05d1\u05d9\u05d5\u05ea\u05e8, \u05d1\u05e7\u05e8 \u05d1\u05db\u05ea\u05d5\u05d1\u05ea {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "\u05d7\u05d3\u05e9", + "Premiere": "\u05d4\u05e7\u05e8\u05e0\u05ea \u05d1\u05db\u05d5\u05e8\u05d4", + "Live": "\u05e9\u05d9\u05d3\u05d5\u05e8 \u05d7\u05d9", + "Repeat": "\u05d7\u05d6\u05d5\u05e8", + "TrackCount": "\u05e9\u05d9\u05e8\u05d9\u05dd {0}", + "ItemCount": "\u05e4\u05e8\u05d9\u05d8\u05d9\u05dd {0}", + "OriginalAirDateValue": "\u05ea\u05d0\u05e8\u05d9\u05da \u05d0\u05d5\u05d5\u05d9\u05e8 \u05de\u05e7\u05d5\u05e8\u05d9: {0}", + "EndsAtValue": "\u05de\u05e1\u05ea\u05d9\u05d9\u05dd \u05d1 {0}", + "HeaderSelectDate": "\u05d1\u05d7\u05e8 \u05ea\u05d0\u05e8\u05d9\u05da", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "\u05d1\u05e1\u05d3\u05e8", + "ButtonCancel": "\u05d1\u05d8\u05dc", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "\u05d4\u05d1\u05e0\u05ea\u05d9", + "ButtonRestart": "\u05d0\u05d9\u05ea\u05d7\u05d5\u05dc", + "RecordingCancelled": "\u05d1\u05d8\u05dc \u05d4\u05e7\u05dc\u05d8\u05d4", + "SeriesCancelled": "\u05d1\u05d8\u05dc \u05e1\u05d3\u05e8\u05d5\u05ea", + "RecordingScheduled": "\u05d4\u05d4\u05e7\u05dc\u05d8\u05d4 \u05de\u05ea\u05d5\u05d6\u05de\u05e0\u05ea.", + "SeriesRecordingScheduled": "\u05d4\u05e7\u05dc\u05d8\u05ea \u05e1\u05d3\u05e8\u05d4 \u05de\u05ea\u05d5\u05d6\u05de\u05e0\u05ea.", + "HeaderNewRecording": "\u05d4\u05e7\u05dc\u05d8\u05d4 \u05d7\u05d3\u05e9\u05d4", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "\u05e8\u05d0\u05e9\u05d5\u05df", + "Monday": "\u05e9\u05e0\u05d9", + "Tuesday": "\u05e9\u05dc\u05d9\u05e9\u05d9", + "Wednesday": "\u05e8\u05d1\u05d9\u05e2\u05d9", + "Thursday": "\u05d7\u05de\u05d9\u05e9\u05d9", + "Friday": "\u05e9\u05d9\u05e9\u05d9", + "Saturday": "\u05e9\u05d1\u05ea", + "Days": "\u05d9\u05de\u05d9\u05dd", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "\u05d4\u05e7\u05dc\u05d8 \u05e1\u05d3\u05e8\u05d4", + "HeaderCinemaMode": "\u05de\u05e6\u05d1 \u05e7\u05d5\u05dc\u05e0\u05d5\u05e2", + "HeaderCloudSync": "\u05e1\u05e0\u05db\u05e8\u05d5\u05df \u05e2\u05e0\u05df", + "Downloads": "\u05d4\u05d5\u05e8\u05d3\u05d5\u05ea", + "HeaderMyDownloads": "My Downloads", + "HeaderOfflineDownloads": "\u05de\u05d3\u05d9\u05d4 \u05dc\u05d0 \u05de\u05e7\u05d5\u05d5\u05e0\u05ea", + "HeaderOfflineDownloadsDescription": "\u05d4\u05d5\u05e8\u05d3 \u05de\u05d3\u05d9\u05d4 \u05dc\u05de\u05db\u05e9\u05d9\u05e8\u05d9\u05dd \u05e9\u05dc\u05da \u05dc\u05e9\u05d9\u05de\u05d5\u05e9 \u05dc\u05d0 \u05de\u05e7\u05d5\u05d5\u05df \u05d1\u05e7\u05dc\u05d5\u05ea.", + "CloudSyncFeatureDescription": "\u05e1\u05e0\u05db\u05e8\u05df \u05d0\u05ea \u05d4\u05de\u05d3\u05d9\u05d4 \u05e9\u05dc\u05da \u05dc\u05e2\u05e0\u05df \u05dc\u05e6\u05d5\u05e8\u05da \u05d2\u05d9\u05d1\u05d5\u05d9 \u05e7\u05dc, \u05d0\u05d7\u05e1\u05d5\u05df \u05d1\u05d0\u05e8\u05db\u05d9\u05d5\u05df \u05d5\u05d4\u05de\u05e8\u05d4.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "CinemaModeFeatureDescription": "\u05de\u05e6\u05d1 \u05e7\u05d5\u05dc\u05e0\u05d5\u05e2 \u05e0\u05d5\u05ea\u05df \u05dc\u05da \u05d0\u05ea \u05d4\u05d7\u05d5\u05d5\u05d9\u05d4 \u05d4\u05e7\u05d5\u05dc\u05e0\u05d5\u05e2 \u05d0\u05de\u05d9\u05ea\u05d9 \u05e2\u05dd \u05e7\u05d3\u05d9\u05de\u05d5\u05e0\u05d9\u05dd \u05de\u05d5\u05ea\u05d0\u05de\u05d9\u05dd \u05d0\u05d9\u05e9\u05d9\u05ea \u05dc\u05e4\u05e0\u05d9 \u05d4\u05ea\u05db\u05d5\u05e0\u05d4.", + "HeaderFreeApps": "\u05d0\u05e4\u05dc\u05d9\u05e7\u05e6\u05d9\u05d5\u05ea \u05d0\u05de\u05d1\u05d9 \u05d1\u05d7\u05d9\u05e0\u05dd", + "FreeAppsFeatureDescription": "\u05d1\u05d0\u05e4\u05e9\u05e8\u05d5\u05ea\u05da \u05dc\u05d9\u05d4\u05e0\u05d5\u05ea \u05de\u05d2\u05d9\u05e9\u05d4 \u05d7\u05d5\u05e4\u05e9\u05d9\u05ea \u05dc\u05d9\u05d9\u05e9\u05d5\u05de\u05d9 Emby \u05e2\u05d1\u05d5\u05e8 \u05d4\u05de\u05db\u05e9\u05d9\u05e8\u05d9\u05dd \u05e9\u05dc\u05da.", + "HeaderBecomeProjectSupporter": "\u05e7\u05d1\u05dc Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "LabelEmailAddress": "\u05db\u05ea\u05d5\u05d1\u05ea \u05d3\u05d5\u05d0\"\u05dc:", + "PromoConvertRecordingsToStreamingFormat": "\u05dc\u05d4\u05de\u05d9\u05e8 \u05d1\u05d0\u05d5\u05e4\u05df \u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9 \u05d4\u05e7\u05dc\u05d8\u05d5\u05ea \u05d1\u05e4\u05d5\u05e8\u05de\u05d8 \u05d6\u05d5\u05e8\u05dd \u05d9\u05d3\u05d9\u05d3\u05d5\u05ea\u05d9 \u05e2\u05dd \u05d0\u05de\u05d1\u05d9 Premiere. \u05d4\u05e7\u05dc\u05d8\u05d5\u05ea \u05d9\u05d5\u05de\u05e8\u05d5 \u05e2\u05dc \u05dc\u05d8\u05d5\u05e1 \u05dc MP4 \u05d0\u05d5 MKV, \u05d1\u05d4\u05ea\u05d1\u05e1\u05e1 \u05e2\u05dc \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e9\u05e8\u05ea \u05d0\u05de\u05d1\u05d9.", + "FeatureRequiresEmbyPremiere": "\u05ea\u05db\u05d5\u05e0\u05d4 \u05d6\u05d5 \u05d3\u05d5\u05e8\u05e9\u05ea \u05de\u05e0\u05d5\u05d9 \u05e4\u05e2\u05d9\u05dc \u05e9\u05dc Emby Premiere.", + "HeaderConvertYourRecordings": "\u05d4\u05de\u05e8\u05ea \u05d4\u05e7\u05dc\u05d8\u05d5\u05ea \u05e9\u05dc\u05da", + "Record": "\u05d4\u05e7\u05dc\u05d8", + "Save": "\u05e9\u05de\u05d5\u05e8", + "Edit": "\u05e2\u05e8\u05d5\u05da", + "Download": "\u05d4\u05d5\u05e8\u05d3\u05d4", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "\u05de\u05ea\u05e7\u05d3\u05dd", + "Delete": "\u05de\u05d7\u05e7", + "HeaderDeleteItem": "\u05de\u05d7\u05e7 \u05e4\u05e8\u05d9\u05d8", + "ConfirmDeleteItem": "\u05de\u05d7\u05d9\u05e7\u05ea \u05e4\u05e8\u05d9\u05d8 \u05d6\u05d4 \u05ea\u05de\u05d7\u05e7 \u05d0\u05d5\u05ea\u05d5 \u05d4\u05df \u05de\u05de\u05e2\u05e8\u05db\u05ea \u05d4\u05e7\u05d1\u05e6\u05d9\u05dd \u05d5\u05d4\u05df \u05de\u05e1\u05e4\u05e8\u05d9\u05d9\u05ea \u05d4\u05de\u05d3\u05d9\u05d4 \u05e9\u05dc\u05da. \u05d4\u05d0\u05dd \u05d0\u05ea\u05d4 \u05d1\u05d8\u05d5\u05d7 \u05e9\u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05de\u05e9\u05d9\u05da?", + "Refresh": "\u05e8\u05e2\u05e0\u05d5\u05df", + "RefreshQueued": "\u05e8\u05e2\u05e0\u05df \u05ea\u05d5\u05e8.", + "AddToCollection": "\u05dc\u05d4\u05d5\u05e1\u05d9\u05e3 \u05dc\u05d0\u05d5\u05e1\u05e3", + "HeaderAddToCollection": "\u05dc\u05d4\u05d5\u05e1\u05d9\u05e3 \u05dc\u05d0\u05d5\u05e1\u05e3", + "NewCollection": "\u05d0\u05d5\u05e1\u05e4\u05d9\u05dd \u05d7\u05d3\u05e9\u05d9\u05dd", + "LabelCollection": "\u05d0\u05d5\u05e1\u05e4\u05d9\u05dd:", + "Help": "\u05e2\u05d6\u05e8\u05d4", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "\u05d0\u05d5\u05e1\u05e4\u05d9\u05dd \u05de\u05d0\u05e4\u05e9\u05e8\u05d9\u05dd \u05dc\u05da \u05dc\u05d9\u05e6\u05d5\u05e8 \u05e7\u05d9\u05d1\u05d5\u05e6\u05d9\u05dd \u05de\u05d5\u05ea\u05d0\u05de\u05d9\u05dd \u05d0\u05d9\u05e9\u05d9\u05ea \u05e9\u05dc \u05e1\u05e8\u05d8\u05d9\u05dd \u05d5\u05ea\u05d5\u05db\u05df \u05e1\u05e4\u05e8\u05d9\u05d4 \u05d0\u05d7\u05e8.", + "SearchForCollectionInternetMetadata": "\u05d7\u05e4\u05e9 \u05d1\u05d0\u05d9\u05e0\u05e8\u05e0\u05d8 \u05d0\u05d7\u05e8\u05d9 \u05de\u05d9\u05d3\u05e2 \u05d5\u05ea\u05de\u05d5\u05e0\u05d5\u05ea", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "\u05e9\u05dd:", + "NewCollectionNameExample": "\u05dc\u05d3\u05d5\u05d2\u05de\u05d0 :\u05d0\u05d5\u05e1\u05e3 \u05de\u05dc\u05d7\u05de\u05ea \u05d4\u05db\u05d5\u05db\u05d1\u05d9\u05dd", + "MessageItemsAdded": "\u05e4\u05e8\u05d9\u05d8\u05d9\u05dd \u05e0\u05d5\u05e1\u05e4\u05d5.", + "OptionNew": "\u05d7\u05d3\u05e9...", + "LabelPlaylist": "\u05e8\u05e9\u05d9\u05de\u05ea \u05e0\u05d9\u05d2\u05d5\u05df:", + "AddToPlaylist": "\u05d4\u05d5\u05e1\u05e3 \u05dc\u05e8\u05e9\u05d9\u05de\u05ea \u05e0\u05d9\u05d2\u05d5\u05df", + "HeaderAddToPlaylist": "\u05d4\u05d5\u05e1\u05e3 \u05dc\u05e8\u05e9\u05d9\u05de\u05ea \u05e0\u05d9\u05d2\u05d5\u05df", + "Subtitles": "\u05db\u05ea\u05d5\u05d1\u05d9\u05d5\u05ea", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "\u05d7\u05d9\u05e4\u05d5\u05e9 \u05e9\u05dc \u05db\u05ea\u05d5\u05d1\u05d9\u05d5\u05ea", + "LabelLanguage": "\u05e9\u05e4\u05d4:", + "Search": "\u05d7\u05d9\u05e4\u05d5\u05e9", + "NoSubtitleSearchResultsFound": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05ea\u05d5\u05e6\u05d0\u05d5\u05ea.", + "File": "\u05e7\u05d5\u05d1\u05e5", + "MessageAreYouSureDeleteSubtitles": "\u05d4\u05d0\u05dd \u05d0\u05ea\u05d4 \u05d1\u05d8\u05d5\u05d7 \u05e9\u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05de\u05d7\u05d5\u05e7 \u05e7\u05d5\u05d1\u05e5 \u05db\u05ea\u05d5\u05d1\u05d9\u05ea \u05d6\u05d4?", + "ConfirmDeletion": "\u05d0\u05e9\u05e8 \u05de\u05d7\u05d9\u05e7\u05d4", + "MySubtitles": "\u05d4\u05db\u05ea\u05d5\u05d1\u05d9\u05d5\u05ea \u05e9\u05dc\u05d9", + "MessageDownloadQueued": "\u05d4\u05d5\u05e8\u05d3 \u05ea\u05d5\u05e8", + "EditSubtitles": "\u05e2\u05e8\u05d5\u05da \u05db\u05ea\u05d5\u05d1\u05d9\u05d5\u05ea", + "UnlockGuide": "\u05e0\u05e2\u05d9\u05dc\u05ea \u05de\u05d3\u05e8\u05d9\u05da", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "\u05d4\u05d7\u05dc\u05e3 \u05ea\u05de\u05d5\u05e0\u05d5\u05ea \u05e7\u05d9\u05d9\u05de\u05d5\u05ea", + "ReplaceAllMetadata": "\u05d4\u05d7\u05dc\u05e3 \u05d0\u05ea \u05db\u05dc \u05d4\u05de\u05d8\u05d0 \u05e0\u05ea\u05d5\u05e0\u05d9\u05dd", + "SearchForMissingMetadata": "\u05d7\u05e4\u05e9 \u05de\u05d8\u05d0 \u05e0\u05ea\u05d5\u05e0\u05d9\u05dd \u05d7\u05e1\u05e8\u05d9\u05dd", + "LabelRefreshMode": "\u05de\u05e6\u05d1 \u05e8\u05e2\u05e0\u05d5\u05df:", + "NoItemsFound": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05e4\u05e8\u05d9\u05d8\u05d9\u05dd", + "HeaderSaySomethingLike": "\u05ea\u05d2\u05d9\u05d3 \u05de\u05e9\u05d4\u05d5 \u05db\u05de\u05d5 ...", + "ButtonTryAgain": "\u05e0\u05e1\u05d4 \u05e9\u05e0\u05d9\u05ea", + "HeaderYouSaid": "\u05d0\u05ea\u05d4 \u05d0\u05de\u05e8\u05ea...", + "MessageWeDidntRecognizeCommand": "\u05d0\u05e0\u05d7\u05e0\u05d5 \u05de\u05e6\u05d8\u05e2\u05e8\u05d9\u05dd, \u05dc\u05d0 \u05d6\u05d9\u05d4\u05d9\u05e0\u05d5 \u05d0\u05ea \u05d4\u05e4\u05e7\u05d5\u05d3\u05d4 \u05d4\u05d6\u05d0\u05ea.", + "MessageIfYouBlockedVoice": "\u05d0\u05dd \u05de\u05e0\u05e2\u05ea \u05d2\u05d9\u05e9\u05d4 \u05e7\u05d5\u05dc\u05d9\u05ea \u05dc\u05d0\u05e4\u05dc\u05d9\u05e7\u05e6\u05d9\u05d4 \u05e9\u05ea\u05e6\u05d8\u05e8\u05da \u05dc\u05d4\u05d2\u05d3\u05d9\u05e8 \u05de\u05d7\u05d3\u05e9 \u05dc\u05e4\u05e0\u05d9 \u05e9\u05ea\u05e0\u05e1\u05d4 \u05e9\u05d5\u05d1.", + "ValueDiscNumber": "\u05d3\u05d9\u05e1\u05e7 {0}", + "Unrated": "\u05d0\u05d9\u05df \u05d3\u05d9\u05e8\u05d5\u05d2", + "Favorite": "\u05de\u05d5\u05e2\u05d3\u05e3", + "Like": "\u05d0\u05d5\u05d4\u05d1", + "Dislike": "\u05dc\u05d0 \u05d0\u05d5\u05d4\u05d1", + "RefreshDialogHelp": "\u05d4\u05de\u05d8\u05d0 \u05e0\u05ea\u05d5\u05e0\u05d9\u05dd \u05de\u05ea\u05e8\u05e2\u05e0\u05e0\u05d9\u05dd \u05e2\u05dc \u05e1\u05de\u05da \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05d5\u05e9\u05d9\u05e8\u05d5\u05ea\u05d9 \u05d0\u05d9\u05e0\u05d8\u05e8\u05e0\u05d8 \u05e9\u05de\u05d5\u05e4\u05e2\u05dc\u05d9\u05dd \u05d1\u05dc\u05d5\u05d7 \u05d4\u05de\u05d7\u05d5\u05d5\u05e0\u05d9\u05dd \u05e9\u05dc \u05de\u05e8\u05db\u05d6 \u05d0\u05de\u05d1\u05d9.", + "Open": "\u05e4\u05ea\u05d7", + "Play": "\u05e0\u05d2\u05df", + "AddToPlayQueue": "\u05d4\u05d5\u05e1\u05e3 \u05dc\u05ea\u05d5\u05e8 \u05d4\u05e4\u05e2\u05dc\u05d4", + "Shuffle": "\u05e2\u05e8\u05d1\u05d1", + "Identify": "\u05dc\u05d6\u05d4\u05d5\u05ea", + "EditImages": "\u05e2\u05e8\u05d5\u05da \u05ea\u05de\u05d5\u05e0\u05d5\u05ea", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "\u05e1\u05e0\u05db\u05e8\u05df", + "InstantMix": "\u05de\u05d9\u05e7\u05e1 \u05de\u05d9\u05d9\u05d3\u05d9", + "ViewAlbum": "\u05e6\u05e4\u05d4 \u05d1\u05d0\u05dc\u05d1\u05d5\u05dd", + "ViewArtist": "\u05e6\u05e4\u05d4 \u05d1\u05d0\u05de\u05df", + "QueueAllFromHere": "\u05d4\u05d5\u05e1\u05e3 \u05d4\u05db\u05dc \u05de\u05db\u05d0\u05df \u05dc\u05ea\u05d5\u05e8", + "PlayAllFromHere": "\u05e0\u05d2\u05df \u05d4\u05db\u05dc \u05de\u05db\u05d0\u05df", + "PlayFromBeginning": "\u05e0\u05d2\u05df \u05de\u05d4\u05ea\u05d7\u05dc\u05d4", + "ResumeAt": "\u05d4\u05de\u05e9\u05da \u05de {0}", + "RemoveFromPlaylist": "\u05d4\u05e1\u05e8 \u05de\u05e8\u05e9\u05d9\u05de\u05ea \u05d4\u05e0\u05d9\u05d2\u05d5\u05df", + "RemoveFromCollection": "\u05d4\u05e1\u05e8 \u05de\u05d0\u05d5\u05e1\u05e4\u05d9\u05dd", + "Sort": "Sort", + "Trailer": "\u05e7\u05d8\u05e2\u05d9 \u05e1\u05e8\u05d8", + "MarkPlayed": "\u05e1\u05de\u05df \u05e0\u05d5\u05d2\u05df", + "MarkUnplayed": "\u05e1\u05de\u05df \u05dc\u05d0 \u05e0\u05d5\u05d2\u05df", + "GroupVersions": "\u05d2\u05e8\u05e1\u05d0\u05d5\u05ea \u05e7\u05d1\u05d5\u05e6\u05ea\u05d9\u05d5\u05ea", + "PleaseSelectTwoItems": "\u05d1\u05d7\u05e8 \u05dc\u05e4\u05d7\u05d5\u05ea \u05e9\u05e0\u05d9 \u05e4\u05e8\u05d9\u05d8\u05d9\u05dd.", + "TryMultiSelect": "\u05e0\u05e1\u05d4 \u05d1\u05d7\u05d9\u05e8\u05d4 \u05de\u05e8\u05d5\u05d1\u05d4", + "TryMultiSelectMessage": "\u05db\u05d3\u05d9 \u05dc\u05e2\u05e8\u05d5\u05da \u05e4\u05e8\u05d9\u05d8\u05d9 \u05de\u05d3\u05d9\u05d4 \u05de\u05e8\u05d5\u05d1\u05d9\u05dd, \u05e4\u05e9\u05d5\u05d8 \u05dc\u05d7\u05e5 \u05dc\u05d7\u05d9\u05e6\u05d4 \u05d0\u05e8\u05d5\u05db\u05d4 \u05e2\u05dc \u05db\u05dc \u05e4\u05d5\u05e1\u05d8\u05e8 \u05d5\u05d1\u05d7\u05e8 \u05d0\u05ea \u05d4\u05e4\u05e8\u05d9\u05d8\u05d9\u05dd \u05e9\u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05e0\u05d4\u05dc. \u05e0\u05e1\u05d4 \u05d6\u05d0\u05ea!", + "HeaderConfirmRecordingCancellation": "\u05d0\u05e9\u05e8 \u05d1\u05d9\u05d8\u05d5\u05dc \u05d4\u05e7\u05dc\u05d8\u05d4", + "MessageConfirmRecordingCancellation": "\u05d4\u05d0\u05dd \u05d0\u05ea\u05d4 \u05d1\u05d8\u05d5\u05d7 \u05e9\u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d1\u05d8\u05dc \u05d4\u05e7\u05dc\u05d8\u05d4 \u05d6\u05d5?", + "Error": "\u05e9\u05d2\u05d9\u05d0\u05d4", + "VoiceInput": "\u05e7\u05dc\u05d8 \u05e7\u05d5\u05dc\u05d9", + "LabelContentType": "\u05e1\u05d5\u05d2 \u05d4\u05ea\u05d5\u05db\u05df", + "LabelPath": "\u05e0\u05ea\u05d9\u05d1:", + "Playlists": "Playlists", + "LabelTitle": "\u05db\u05d5\u05ea\u05e8\u05ea:", + "LabelOriginalTitle": "\u05db\u05d5\u05ea\u05e8\u05ea \u05de\u05e7\u05d5\u05e8\u05d9\u05ea:", + "LabelSortTitle": "\u05de\u05d9\u05d9\u05df \u05db\u05d5\u05ea\u05e8\u05ea:", + "LabelDateAdded": "\u05ea\u05d0\u05e8\u05d9\u05da \u05d4\u05d5\u05e1\u05e3:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "\u05d4\u05d2\u05d3\u05e8 \u05db\u05d9\u05e6\u05d3 \u05ea\u05d0\u05e8\u05d9\u05da \u05d4\u05ea\u05d5\u05e1\u05e4\u05ea \u05e0\u05e7\u05d1\u05e2 \u05d1\u05dc\u05d5\u05d7 \u05d4\u05de\u05d7\u05d5\u05d5\u05e0\u05d9\u05dd \u05e9\u05dc \u05e9\u05e8\u05ea Amby \u05ea\u05d7\u05ea \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e1\u05e4\u05e8\u05d9\u05d4", + "LabelStatus": "\u05e1\u05d8\u05d8\u05d5\u05e1:", + "LabelArtists": "\u05d0\u05d5\u05de\u05e0\u05d9\u05dd:", + "LabelArtistsHelp": "\u05d4\u05e4\u05e8\u05d3 \u05de\u05e8\u05d5\u05d1\u05d9\u05dd \u05d1\u05d0\u05de\u05e6\u05e2\u05d5\u05ea;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "\u05d0\u05dc\u05d1\u05d5\u05dd \u05d0\u05d5\u05de\u05e0\u05d9\u05dd:", + "LabelAlbum": "\u05d0\u05dc\u05d1\u05d5\u05dd:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "\u05d3\u05d9\u05e8\u05d5\u05d2 \u05d4\u05e7\u05d4\u05d9\u05dc\u05d4:", + "LabelCriticRating": "\u05d3\u05d9\u05e8\u05d5\u05d2 \u05d1\u05d9\u05e7\u05d5\u05e8\u05ea:", + "CriticRating": "Critic rating", + "LabelWebsite": "\u05d0\u05ea\u05e8:", + "LabelTagline": "\u05e9\u05d5\u05e8\u05ea \u05ea\u05d9\u05d5\u05d2:", + "LabelOverview": "\u05e1\u05e7\u05d9\u05e8\u05d4 \u05db\u05dc\u05dc\u05d9\u05ea:", + "LabelShortOverview": "\u05e1\u05e7\u05d9\u05e8\u05d4 \u05e7\u05e6\u05e8\u05d4:", + "LabelReleaseDate": "\u05ea\u05d0\u05e8\u05d9\u05da \u05d4\u05d5\u05e6\u05d0\u05d4:", + "LabelYear": "\u05e9\u05e0\u05d4:", + "LabelPlaceOfBirth": "\u05de\u05e7\u05d5\u05dd \u05dc\u05d9\u05d3\u05d4:", + "Aired": "Aired", + "LabelAirDays": "\u05d9\u05de\u05d9 \u05d0\u05d5\u05d9\u05e8:", + "LabelAirTime": "\u05d6\u05de\u05df \u05d0\u05d5\u05d5\u05d9\u05e8:", + "LabelRuntimeMinutes": "\u05d6\u05de\u05df \u05e8\u05d9\u05e6\u05d4 (\u05d3\u05e7\u05d5\u05ea):", + "LabelParentalRating": "\u05d3\u05d9\u05e8\u05d5\u05d2 \u05d4\u05d4\u05d5\u05e8\u05d9\u05dd:", + "LabelCustomRating": "\u05d3\u05d9\u05e8\u05d5\u05d2 \u05de\u05d5\u05ea\u05d0\u05dd \u05d0\u05d9\u05e9\u05d9\u05ea:", + "LabelOriginalAspectRatio": "\u05d9\u05d7\u05e1 \u05d2\u05d5\u05d1\u05d4-\u05e8\u05d5\u05d7\u05d1 \u05de\u05e7\u05d5\u05e8\u05d9:", + "Label3DFormat": "\u05e4\u05d5\u05e8\u05de\u05d8 \u05ea\u05dc\u05ea-\u05de\u05de\u05d3\u05d9:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "\u05e4\u05e8\u05d8\u05d9 \u05d0\u05e4\u05d9\u05d6\u05d5\u05d3\u05d5\u05ea \u05de\u05d9\u05d5\u05d7\u05d3\u05d5\u05ea", + "LabelAirsBeforeSeason": "\u05d1\u05d0\u05d5\u05d5\u05d9\u05e8 \u05dc\u05e4\u05e0\u05d9 \u05d4\u05e2\u05d5\u05e0\u05d4:", + "LabelAirsAfterSeason": "\u05d1\u05d0\u05d5\u05d5\u05d9\u05e8 \u05d0\u05d7\u05e8\u05d9 \u05d4\u05e2\u05d5\u05e0\u05d4:", + "LabelAirsBeforeEpisode": "\u05d1\u05d0\u05d5\u05d5\u05d9\u05e8 \u05dc\u05e4\u05e0\u05d9 \u05e4\u05e8\u05e7:", + "HeaderExternalIds": "\u05de\u05d6\u05d4\u05d9\u05dd \u05d7\u05d9\u05e6\u05d5\u05e0\u05d9\u05d9\u05dd:", + "HeaderDisplaySettings": "\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05ea\u05e6\u05d5\u05d2\u05d4", + "LabelDisplayOrder": "\u05e1\u05d3\u05e8 \u05ea\u05e6\u05d5\u05d2\u05d4:", + "Display": "Display", + "Countries": "\u05de\u05d3\u05d9\u05e0\u05d5\u05ea", + "Genres": "\u05d6'\u05d0\u05e0\u05e8\u05d9\u05dd", + "Studios": "\u05d0\u05d5\u05dc\u05e4\u05e0\u05d9", + "Tags": "\u05ea\u05d2\u05d9\u05dd", + "HeaderMetadataSettings": "\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05de\u05d8\u05d0 \u05e0\u05ea\u05d5\u05e0\u05d9\u05dd", + "People": "\u05d0\u05e0\u05e9\u05d9\u05dd", + "LabelMetadataDownloadLanguage": "\u05e9\u05e4\u05ea \u05d4\u05d5\u05e8\u05d3\u05d4 \u05de\u05d5\u05e2\u05d3\u05e4\u05ea:", + "LabelLockItemToPreventChanges": "\u05e0\u05e2\u05dc \u05e4\u05e8\u05d9\u05d8 \u05d6\u05d4 \u05db\u05d3\u05d9 \u05dc\u05de\u05e0\u05d5\u05e2 \u05e9\u05d9\u05e0\u05d5\u05d9\u05d9\u05dd \u05e2\u05ea\u05d9\u05d3\u05d9\u05d9\u05dd", + "MessageLeaveEmptyToInherit": "\u05d4\u05e9\u05d0\u05e8 \u05e8\u05d9\u05e7 \u05db\u05d3\u05d9 \u05dc\u05e8\u05e9\u05ea \u05d0\u05ea \u05d4\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05de\u05e4\u05e8\u05d9\u05d8 \u05d0\u05d1, \u05d0\u05d5 \u05d0\u05ea \u05e2\u05e8\u05da \u05d1\u05e8\u05d9\u05e8\u05ea \u05d4\u05de\u05d7\u05d3\u05dc \u05d4\u05d2\u05dc\u05d5\u05d1\u05dc\u05d9.", + "LabelCountry": "\u05de\u05d3\u05d9\u05e0\u05d4:", + "LabelDynamicExternalId": "{0} \u05ea\u05e2\u05d5\u05d3\u05ea \u05d6\u05d4\u05d5\u05ea:", + "LabelBirthYear": "\u05e9\u05e0\u05ea \u05dc\u05d9\u05d3\u05d4:", + "LabelBirthDate": "\u05ea\u05d0\u05e8\u05d9\u05da \u05dc\u05d9\u05d3\u05d4:", + "LabelDeathDate": "\u05ea\u05d0\u05e8\u05d9\u05da \u05d4\u05de\u05d5\u05d5\u05ea:", + "LabelEndDate": "\u05ea\u05d0\u05e8\u05d9\u05da \u05e1\u05d9\u05d5\u05dd:", + "LabelSeasonNumber": "\u05de\u05e1\u05e4\u05e8 \u05e2\u05d5\u05e0\u05d4:", + "LabelEpisodeNumber": "\u05de\u05e1\u05e4\u05e8 \u05e4\u05e8\u05e7:", + "LabelTrackNumber": "\u05e7\u05d8\u05e2 \u05de\u05e1\u05e4\u05e8:", + "LabelNumber": "\u05de\u05e1\u05e4\u05e8:", + "LabelDiscNumber": "\u05de\u05e1\u05e4\u05e8 \u05d3\u05d9\u05e1\u05e7:", + "LabelParentNumber": "\u05de\u05e1\u05e4\u05e8 \u05d0\u05d1:", + "SortName": "\u05de\u05d9\u05d9\u05df \u05dc\u05e4\u05d9 \u05e9\u05dd", + "ReleaseDate": "\u05ea\u05d0\u05e8\u05d9\u05da \u05e9\u05d9\u05d7\u05e8\u05d5\u05e8", + "Continuing": "\u05de\u05de\u05e9\u05d9\u05da", + "Ended": "\u05d4\u05e1\u05ea\u05d9\u05d9\u05dd", + "HeaderEnabledFields": "\u05e9\u05d3\u05d5\u05ea \u05d6\u05de\u05d9\u05e0\u05d9\u05dd", + "HeaderEnabledFieldsHelp": "\u05d1\u05d8\u05dc \u05d0\u05ea \u05d4\u05e1\u05d9\u05de\u05d5\u05df \u05d1\u05e9\u05d3\u05d4 \u05db\u05d3\u05d9 \u05dc\u05e0\u05e2\u05d5\u05dc \u05d0\u05d5\u05ea\u05d5 \u05d5\u05dc\u05de\u05e0\u05d5\u05e2 \u05e9\u05d9\u05e0\u05d5\u05d9 \u05d1\u05e0\u05ea\u05d5\u05e0\u05d9\u05dd.", + "Backdrops": "\u05ea\u05e4\u05d0\u05d5\u05e8\u05d5\u05ea", + "Images": "\u05ea\u05de\u05d5\u05e0\u05d5\u05ea", + "Runtime": "\u05d6\u05de\u05df \u05e8\u05d9\u05e6\u05d4", + "ProductionLocations": "\u05de\u05d9\u05e7\u05d5\u05de\u05d9 \u05d9\u05d9\u05e6\u05d5\u05e8", + "BirthLocation": "\u05de\u05d9\u05e7\u05d5\u05dd \u05dc\u05d9\u05d3\u05d4", + "ParentalRating": "\u05d3\u05d9\u05e8\u05d5\u05d2 \u05d4\u05d4\u05d5\u05e8\u05d9\u05dd", + "PlayCount": "Play count", + "Name": "\u05e9\u05dd", + "Overview": "\u05e1\u05e7\u05d9\u05e8\u05d4 \u05db\u05dc\u05dc\u05d9\u05ea", + "LabelType": "\u05e1\u05d5\u05d2:", + "LabelPersonRole": "\u05ea\u05e4\u05e7\u05d9\u05d3:", + "LabelPersonRoleHelp": "\u05d3\u05d5\u05d2\u05de\u05d4: \u05e0\u05d4\u05d2 \u05de\u05e9\u05d0\u05d9\u05ea \u05d2\u05dc\u05d9\u05d3\u05d4", + "Actor": "\u05e9\u05d7\u05e7\u05df", + "Composer": "\u05de\u05dc\u05d7\u05d9\u05df", + "Director": "\u05de\u05e0\u05d4\u05dc", + "GuestStar": "\u05db\u05d5\u05db\u05d1 \u05d0\u05d5\u05e8\u05d7", + "Producer": "\u05d1\u05de\u05d0\u05d9", + "Writer": "\u05db\u05d5\u05ea\u05d1", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "\u05de\u05ea\u05e7\u05d9\u05df {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "\u05d4\u05d4\u05ea\u05e7\u05e0\u05d4 {0} \u05e0\u05db\u05e9\u05dc\u05d4.", + "PackageInstallCancelled": "{0} \u05d4\u05d4\u05ea\u05e7\u05e0\u05d4 \u05d1\u05d5\u05d8\u05dc\u05d4.", + "SeriesYearToPresent": "{0} - \u05d4\u05d9\u05d5\u05dd", + "ValueOneItem": "\u05e4\u05e8\u05d9\u05d8 1", + "ValueOneSong": "\u05e9\u05d9\u05e8 1", + "ValueSongCount": "{0} \u05e9\u05d9\u05e8\u05d9\u05dd", + "ValueOneMovie": "\u05e1\u05e8\u05d8 1", + "ValueMovieCount": "{0} \u05e1\u05e8\u05d8\u05d9\u05dd", + "ValueOneSeries": "1 \u05e1\u05d3\u05e8\u05d4", + "ValueSeriesCount": "{0} \u05e1\u05d3\u05e8\u05d5\u05ea", + "ValueOneEpisode": "\u05e4\u05e8\u05e7 1", + "ValueEpisodeCount": "{0} \u05e4\u05e8\u05e7\u05d9\u05dd", + "ValueOneGame": "\u05de\u05e9\u05d7\u05e7 1", + "ValueGameCount": "{0} \u05de\u05e9\u05d7\u05e7\u05d9\u05dd", + "ValueOneAlbum": "\u05d0\u05dc\u05d1\u05d5\u05dd 1", + "ValueAlbumCount": "{0} \u05d0\u05dc\u05d1\u05d5\u05de\u05d9\u05dd", + "ValueOneMusicVideo": "\u05d5\u05d9\u05d3\u05d0\u05d5 \u05e7\u05dc\u05d9\u05e4 1", + "ValueMusicVideoCount": "{0} \u05d5\u05d9\u05d3\u05d0\u05d5 \u05e7\u05dc\u05d9\u05e4\u05d9\u05dd", + "ValueMinutes": "{0} \u05d3\u05e7\u05d5\u05ea", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "\u05d4\u05d6\u05df \u05e7\u05e8\u05d9\u05d8\u05e8\u05d9\u05d5\u05df \u05d7\u05d9\u05e4\u05d5\u05e9 \u05d0\u05d7\u05d3 \u05d0\u05d5 \u05d9\u05d5\u05ea\u05e8. \u05d4\u05e1\u05e8 \u05e7\u05e8\u05d9\u05d8\u05e8\u05d9\u05d5\u05e0\u05d9\u05dd \u05db\u05d3\u05d9 \u05dc\u05d4\u05d2\u05d3\u05d9\u05dc \u05d0\u05ea \u05ea\u05d5\u05e6\u05d0\u05d5\u05ea \u05d4\u05d7\u05d9\u05e4\u05d5\u05e9.", + "PleaseEnterNameOrId": "\u05d4\u05d6\u05df \u05e9\u05dd \u05d0\u05d5 \u05de\u05d6\u05d4\u05d4 \u05d7\u05d9\u05e6\u05d5\u05e0\u05d9.", + "MessageItemSaved": "\u05d4\u05e4\u05e8\u05d9\u05d8 \u05e0\u05e9\u05de\u05e8.", + "SearchResults": "\u05ea\u05d5\u05e6\u05d0\u05d5\u05ea \u05d7\u05d9\u05e4\u05d5\u05e9", + "ServerNameIsRestarting": "\u05e9\u05e8\u05ea Emby - {0} \u05de\u05d5\u05e4\u05e2\u05dc \u05de\u05d7\u05d3\u05e9.", + "ServerNameIsShuttingDown": "\u05e9\u05e8\u05ea Emby - {0} \u05e0\u05db\u05d1\u05d4.", + "HeaderDeleteItems": "\u05de\u05d7\u05d9\u05e7\u05ea \u05e4\u05e8\u05d9\u05d8\u05d9\u05dd", + "ConfirmDeleteItems": "\u05de\u05d7\u05d9\u05e7\u05ea \u05e4\u05e8\u05d9\u05d8\u05d9\u05dd \u05d0\u05dc\u05d4 \u05ea\u05de\u05d7\u05e7 \u05d0\u05d5\u05ea\u05dd \u05d4\u05df \u05de\u05de\u05e2\u05e8\u05db\u05ea \u05d4\u05e7\u05d1\u05e6\u05d9\u05dd \u05d5\u05d4\u05df \u05de\u05e1\u05e4\u05e8\u05d9\u05d9\u05ea \u05d4\u05de\u05d3\u05d9\u05d4 \u05e9\u05dc\u05da. \u05d4\u05d0\u05dd \u05d0\u05ea\u05d4 \u05d1\u05d8\u05d5\u05d7 \u05e9\u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05de\u05e9\u05d9\u05da?", + "PleaseRestartServerName": "\u05d0\u05e0\u05d0 \u05d4\u05e4\u05e2\u05dc \u05de\u05d7\u05d3\u05e9 \u05d0\u05ea \u05e9\u05e8\u05ea Emby - {0}.", + "LabelSyncJobName": "\u05e1\u05e0\u05db\u05e8\u05df \u05d0\u05ea \u05e9\u05dd \u05d4\u05e2\u05d1\u05d5\u05d3\u05d4:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "\u05d0\u05d9\u05db\u05d5\u05ea:", + "LabelSyncNoTargetsHelp": "\u05e0\u05e8\u05d0\u05d4 \u05e9\u05d0\u05d9\u05df \u05dc\u05da \u05db\u05e8\u05d2\u05e2 \u05d0\u05e4\u05dc\u05d9\u05e7\u05e6\u05d9\u05d5\u05ea \u05d4\u05ea\u05d5\u05de\u05db\u05d5\u05ea \u05d1\u05d4\u05d5\u05e8\u05d3\u05d4 \u05d1\u05de\u05e6\u05d1 \u05dc\u05d0 \u05de\u05e7\u05d5\u05d5\u05df.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "\u05dc\u05de\u05d3 \u05e2\u05d5\u05d3", + "LabelProfile": "\u05e4\u05e8\u05d5\u05e4\u05d9\u05dc:", + "LabelBitrateMbps": "\u05e7\u05e6\u05d1 \u05e1\u05d9\u05d1\u05d9\u05d5\u05ea (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "\u05e8\u05e7 \u05e1\u05e8\u05d8\u05d5\u05e0\u05d9\u05dd \u05e9\u05dc\u05d0 \u05d4\u05d5\u05e8\u05d3\u05d5 \u05d9\u05d5\u05e8\u05d3\u05d5, \u05d5\u05e1\u05e8\u05d8\u05d5\u05e0\u05d9\u05dd \u05d9\u05d5\u05e1\u05e8\u05d5 \u05de\u05d4\u05de\u05db\u05e9\u05d9\u05e8 \u05db\u05e4\u05d9 \u05e9\u05d4\u05dd \u05e6\u05e4\u05d5.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "\u05ea\u05d5\u05db\u05df \u05d7\u05d3\u05e9 \u05e9\u05e0\u05d5\u05e1\u05e3 \u05dc\u05ea\u05d9\u05e7\u05d9\u05d4 \u05d6\u05d5 \u05d9\u05d5\u05e8\u05d9\u05d3 \u05d1\u05d0\u05d5\u05e4\u05df \u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9 \u05dc\u05de\u05db\u05e9\u05d9\u05e8.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "\u05de\u05d2\u05d1\u05dc\u05ea \u05e4\u05e8\u05d9\u05d8:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "\u05d1\u05d7\u05e8 \u05de\u05db\u05e9\u05d9\u05e8 \u05dc\u05d4\u05d5\u05e8\u05d3\u05d4 \u05d0\u05dc\u05d9\u05d5.", + "Screenshots": "\u05e6\u05d9\u05dc\u05d5\u05de\u05d9 \u05de\u05e1\u05da", + "MoveRight": "\u05d6\u05d5\u05d6 \u05d9\u05de\u05d9\u05e0\u05d4", + "MoveLeft": "\u05d6\u05d5\u05d6 \u05e9\u05de\u05d0\u05dc\u05d4", + "ConfirmDeleteImage": "\u05dc\u05de\u05d7\u05d5\u05e7 \u05d0\u05ea \u05d4\u05ea\u05de\u05d5\u05e0\u05d4?", + "HeaderEditImages": "\u05e2\u05e8\u05d5\u05da \u05ea\u05de\u05d5\u05e0\u05d5\u05ea", + "Settings": "\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea", + "ShowIndicatorsFor": "\u05d4\u05e6\u05d2 \u05de\u05d7\u05d5\u05d5\u05e0\u05d9\u05dd \u05e2\u05d1\u05d5\u05e8:", + "NewEpisodes": "\u05e4\u05e8\u05e7\u05d9\u05dd \u05d7\u05d3\u05e9\u05d9\u05dd", + "Episodes": "Episodes", + "HDPrograms": "\u05ea\u05d5\u05db\u05e0\u05d9\u05d5\u05ea HD", + "Programs": "Programs", + "LiveBroadcasts": "\u05e9\u05d9\u05d3\u05d5\u05e8\u05d9\u05dd \u05d7\u05d9\u05d9\u05dd", + "Premieres": "\u05d1\u05db\u05d5\u05e8\u05d5\u05ea", + "RepeatEpisodes": "\u05d7\u05d6\u05d5\u05e8 \u05e2\u05dc \u05e4\u05e8\u05e7\u05d9\u05dd", + "DvrSubscriptionRequired": "\u05d0\u05de\u05d1\u05d9 DVR \u05d3\u05d5\u05e8\u05e9\u05ea \u05de\u05e0\u05d5\u05d9 \u05e4\u05e2\u05d9\u05dc \u05e9\u05dc Emby Premiere.", + "HeaderCancelRecording": "\u05d1\u05d9\u05d8\u05d5\u05dc \u05d4\u05e7\u05dc\u05d8\u05d4", + "CancelRecording": "\u05d1\u05d9\u05d8\u05d5\u05dc \u05d4\u05e7\u05dc\u05d8\u05d4", + "HeaderKeepRecording": "\u05e9\u05de\u05d5\u05e8 \u05e2\u05dc \u05d4\u05e7\u05dc\u05d8\u05d4", + "HeaderCancelSeries": "\u05d1\u05d8\u05dc \u05e1\u05d3\u05e8\u05d4", + "HeaderKeepSeries": "\u05e9\u05de\u05d5\u05e8 \u05e1\u05d3\u05e8\u05d4", + "HeaderLearnMore": "\u05dc\u05de\u05d3 \u05e2\u05d5\u05d3", + "DeleteMedia": "\u05de\u05d7\u05e7 \u05de\u05d3\u05d9\u05d4", + "SeriesSettings": "\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e1\u05d3\u05e8\u05d4", + "HeaderRecordingOptions": "\u05d0\u05e4\u05e9\u05e8\u05d5\u05d9\u05d5\u05ea \u05d4\u05e7\u05dc\u05d8\u05d4", + "CancelSeries": "\u05d1\u05d8\u05dc \u05e1\u05d3\u05e8\u05d4", + "DoNotRecord": "\u05d0\u05dc \u05ea\u05e7\u05dc\u05d9\u05d8", + "HeaderSeriesOptions": "\u05d0\u05e4\u05e9\u05e8\u05d5\u05d9\u05d5\u05ea \u05e1\u05d3\u05e8\u05d4", + "LabelChannels": "\u05e2\u05e8\u05d5\u05e6\u05d9\u05dd:", + "ChannelNameOnly": "\u05e2\u05e8\u05d5\u05e5 {0} \u05d1\u05dc\u05d1\u05d3", + "Anytime": "\u05d1\u05db\u05dc \u05e2\u05ea", + "AnyLanguage": "Any language", + "AroundTime": "\u05d1\u05e1\u05d1\u05d9\u05d1\u05d5\u05ea {0}", + "All": "All", + "AllChannels": "\u05db\u05dc \u05d4\u05e2\u05e8\u05d5\u05e6\u05d9\u05dd", + "LabelRecord": "\u05d4\u05e7\u05dc\u05d8\u05d4:", + "NewEpisodesOnly": "\u05e4\u05e8\u05e7\u05d9\u05dd \u05d7\u05d3\u05e9\u05d9\u05dd \u05d1\u05dc\u05d1\u05d3", + "AllEpisodes": "\u05db\u05dc \u05d4\u05e4\u05e8\u05e7\u05d9\u05dd", + "LabelStartWhenPossible": "\u05d4\u05ea\u05d7\u05dc \u05d1\u05e8\u05d2\u05e2 \u05e9\u05e0\u05d9\u05ea\u05df:", + "LabelStopWhenPossible": "\u05d4\u05e4\u05e1\u05e7 \u05d1\u05e8\u05d2\u05e2 \u05e9\u05d0\u05e4\u05e9\u05e8", + "MinutesBefore": "\u05d3\u05e7\u05d5\u05ea \u05dc\u05e4\u05e0\u05d9", + "MinutesAfter": "\u05d3\u05e7\u05d5\u05ea \u05d0\u05d7\u05e8\u05d9", + "SkipEpisodesAlreadyInMyLibrary": "\u05d0\u05dc \u05ea\u05e7\u05dc\u05d9\u05d8\u05d5 \u05e4\u05e8\u05e7\u05d9\u05dd \u05e9\u05db\u05d1\u05e8 \u05e0\u05de\u05e6\u05d0\u05d9\u05dd \u05d1\u05e1\u05e4\u05e8\u05d9\u05d9\u05d4 \u05e9\u05dc\u05d9", + "SkipEpisodesAlreadyInMyLibraryHelp": "\u05e4\u05e8\u05e7\u05d9\u05dd \u05d9\u05d5\u05e9\u05d5\u05d5 \u05d1\u05d0\u05de\u05e6\u05e2\u05d5\u05ea \u05d4\u05e2\u05d5\u05e0\u05d4 \u05d5\u05d0\u05ea \u05d4\u05e4\u05e8\u05e7 \u05e4\u05e8\u05e7, \u05db\u05d0\u05e9\u05e8 \u05d6\u05de\u05d9\u05df.", + "LabelKeepUpTo": "\u05e9\u05de\u05d5\u05e8 \u05e2\u05d3 \u05dc:", + "AsManyAsPossible": "\u05db\u05de\u05d4 \u05e9\u05d9\u05d5\u05ea\u05e8", + "DefaultErrorMessage": "\u05d0\u05d9\u05e8\u05e2\u05d4 \u05e9\u05d2\u05d9\u05d0\u05d4 \u05d1\u05e2\u05d9\u05d1\u05d5\u05d3 \u05d4\u05d1\u05e7\u05e9\u05d4. \u05d1\u05d1\u05e7\u05e9\u05d4 \u05e0\u05e1\u05d4 \u05e9\u05d5\u05d1 \u05de\u05d0\u05d5\u05d7\u05e8 \u05d9\u05d5\u05ea\u05e8.", + "LabelKeep:": "\u05e9\u05de\u05d5\u05e8:", + "UntilIDelete": "\u05e2\u05d3 \u05e9\u05d0\u05de\u05d7\u05e7", + "UntilSpaceNeeded": "\u05e2\u05d3 \u05d4\u05e6\u05d5\u05e8\u05da \u05d1\u05de\u05e8\u05d7\u05d1", + "Categories": "\u05e7\u05d8\u05d2\u05d5\u05e8\u05d9\u05d5\u05ea", + "Sports": "\u05e1\u05e4\u05d5\u05e8\u05d8", + "News": "\u05d7\u05d3\u05e9\u05d5\u05ea", + "Movies": "\u05e1\u05e8\u05d8\u05d9\u05dd", + "Kids": "\u05d9\u05dc\u05d3\u05d9\u05dd", + "EnableColorCodedBackgrounds": "\u05d0\u05e4\u05e9\u05e8 \u05e8\u05e7\u05e2 \u05d1\u05e6\u05d1\u05e2 \u05de\u05e7\u05d5\u05d3\u05d3", + "SortChannelsBy": "\u05de\u05d9\u05d9\u05df \u05e2\u05e8\u05d5\u05e6\u05d9\u05dd \u05dc\u05e4\u05d9:", + "RecentlyWatched": "\u05e0\u05e6\u05e4\u05d4 \u05dc\u05d0\u05d7\u05e8\u05d5\u05e0\u05d4", + "ChannelNumber": "\u05de\u05e1\u05e4\u05e8 \u05e2\u05e8\u05d5\u05e5", + "HeaderBenefitsEmbyPremiere": "\u05d4\u05d9\u05ea\u05e8\u05d5\u05e0\u05d5\u05ea \u05e9\u05dc \u05d0\u05de\u05d1\u05d9 Premiere", + "ThankYouForTryingEnjoyOneMinute": "\u05d0\u05e0\u05d0 \u05dc\u05d9\u05d4\u05e0\u05d5\u05ea \u05d3\u05e7\u05d4 \u05d0\u05d7\u05ea \u05e9\u05dc \u05d4\u05e9\u05de\u05e2\u05d4. \u05ea\u05d5\u05d3\u05d4 \u05e9\u05e0\u05d9\u05e1\u05d9\u05ea \u05d0\u05ea \u05d0\u05de\u05d1\u05d9.", + "HeaderTryPlayback": "\u05e0\u05e1\u05d4 \u05d4\u05e4\u05e2\u05dc\u05d4", + "HowDidYouPay": "\u05d0\u05d9\u05da \u05e9\u05d9\u05dc\u05de\u05ea?", + "IHaveEmbyPremiere": "\u05d9\u05e9 \u05dc\u05d9 \u05d0\u05de\u05d1\u05d9 Premiere", + "IPurchasedThisApp": "\u05e8\u05db\u05e9\u05ea\u05d9 \u05d0\u05ea \u05d4\u05d0\u05e4\u05dc\u05d9\u05e7\u05e6\u05d9\u05d4 \u05d4\u05d6\u05d5", + "ButtonRestorePreviousPurchase": "\u05e9\u05d7\u05d6\u05e8 \u05e8\u05db\u05d9\u05e9\u05d4", + "ButtonUnlockWithPurchase": "Unlock with Purchase", + "ButtonUnlockPrice": "Unlock {0}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "\u05e1\u05e0\u05db\u05e8\u05df \u05dc:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/hr.json b/src/bower_components/emby-webcomponents/strings/hr.json index d937a114c8..127bf9043b 100644 --- a/src/bower_components/emby-webcomponents/strings/hr.json +++ b/src/bower_components/emby-webcomponents/strings/hr.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Glumac", - "Add": "Dodaj", - "AddToCollection": "Dodaj u kolekciju", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Dodaj u popis", - "AddedOnValue": "Added {0}", - "Advanced": "Napredno", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "Svi kanali", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Sve epizode", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Bilo kada", - "AroundTime": "Oko {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "Što više je moguće", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "Novo", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Pozadine", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Lokacije rođenja", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Odustani", - "ButtonGotIt": "Shvaćam", - "ButtonOk": "U redu", - "ButtonPlayOneMinute": "Reproduciraj jednu minutu", - "ButtonRestart": "Ponovo pokreni", - "ButtonRestorePreviousPurchase": "Vrati kupovinu", - "ButtonTryAgain": "Pokušajte ponovo", - "ButtonUnlockPrice": "Otključaj {0}", - "ButtonUnlockWithPurchase": "Otključaj s kupovinom", - "CancelDownload": "Cancel download", - "CancelRecording": "Prekini snimanje", - "CancelSeries": "Odustani od serije", - "Categories": "Kategorije", - "ChannelNameOnly": "Kanali {0} samo", - "ChannelNumber": "Broj kanala", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Kino način vam daje pravi doživljaj kina s kratkim filmovima i prilagođenim isječcima prije odabrane značajke.", - "CloudSyncFeatureDescription": "Sinkronizirajte svoje medije na oblaku za jednostavni backup, arhiviranje i konvertiranje.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Kompozitor", - "ConfigureDateAdded": "Podesite kako se datum dodavanja određuje na nadzornoj ploči Jellyfin Server-a u postavkama biblioteke", - "ConfirmDeleteImage": "Izbriši sliku?", - "ConfirmDeleteItem": "Brisanjem ove stavke će je izbrisati iz oba datotečnog sustava i medijskoj biblioteci. Jeste li sigurni da želite nastaviti?", - "ConfirmDeleteItems": "Brisanjem ove stavke će se izbrisati iz oba datotečnog sustava i medijskoj biblioteci. Jeste li sigurni da želite nastaviti?", - "ConfirmDeletion": "Potvrdite brisanje", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Nastavlja se", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Zemlje", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Dani", - "Default": "Default", - "DefaultErrorMessage": "Došlo je do pogreške prilikom obrade zahtjeva. Molimo pokušajte ponovo kasnije.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Izbriši", - "DeleteMedia": "Izbriši medij", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Režiser", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Ne sviđa mi se", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Ne snimi", - "Down": "Down", - "Download": "Preuzimanje", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR zahtijeva aktivnu pretplatu Jellyfin Premijere.", - "Edit": "Izmjeni", - "EditImages": "Uređivanje slika", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Uredi titlove", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Omogući kodirane boje pozadine", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Završeno", - "EndsAtValue": "Završava u {0}", - "Episodes": "Episodes", - "Error": "Greška", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Omiljeni", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "Ova značajka zahtijeva aktivnu pretplatu Jellyfin Premijere.", - "Features": "Features", - "File": "Datoteka", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Uživajte u slobodnom pristupu Jellyfin aplikacija za svoje uređaje.", - "Friday": "Petak", - "GenreValue": "Genre: {0}", - "Genres": "Žanrovi", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Verzija grupe", - "GuestStar": "Zvijezda gost", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programi", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Dodaj u kolekciju", - "HeaderAddToPlaylist": "Dodaj u popis", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Nabavite Jellyfin Premijeru", - "HeaderBenefitsJellyfinPremiere": "Prednosti Jellyfin premijere", - "HeaderCancelRecording": "Prekini snimanje", - "HeaderCancelSeries": "Otkaži serije", - "HeaderCinemaMode": "Kino način", - "HeaderCloudSync": "Sink. preko oblaka", - "HeaderConfirmRecordingCancellation": "Potvrdi otkazivanje snimanja", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Konvertiraj snimke", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Izbriši stavku", - "HeaderDeleteItems": "Brisanje stavki", - "HeaderDisplaySettings": "Postavke prikaza", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Uređivanje slika", - "HeaderEnabledFields": "Omogući polja", - "HeaderEnabledFieldsHelp": "Poništi polje za zaključavanje i spriječi njihove podatke od toga da budu promijenjeni.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Besplatne Jellyfin aplikacije", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Unesite jednu ili više kriterija pretraživanja. Uklonite kriterije za povećanje rezultata pretraživanja.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Zadrži snimanje", - "HeaderKeepSeries": "Zadrži serije", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Nauči još", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Postavke meta-podataka", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "Nova snimka", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Izvanmrežni mediji", - "HeaderOfflineDownloadsDescription": "Preuzimanje medija na svojim uređajima za jednostavnu upotrebu izvan mreže.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Reproduciraj moje medije", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Opcije snimanja", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Reci nešto poput...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Odaberi datum", - "HeaderSeriesOptions": "Opcije serija", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Posebni podaci o epizodi", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Isprobajte reprodukciju", - "HeaderUnlockFeature": "Otključaj značajke", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "Rekao si...", - "Help": "Pomoć", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "Kako ste platili?", - "IHaveJellyfinPremiere": "Imam Jellyfin Premijeru", - "IPurchasedThisApp": "Kupio sam ovu aplikaciju", - "Identify": "Identificiraj", - "Images": "Slike", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Instaliranje {0}", - "InstantMix": "Trenutno miješanje", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} stavaka", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Djeca", - "Label3DFormat": "3D format:", - "LabelAirDays": "Dani emitiranja:", - "LabelAirTime": "Vrijeme emitiranja:", - "LabelAirsAfterSeason": "Emitiranje nakon sezona:", - "LabelAirsBeforeEpisode": "Emitiranje prije epizoda:", - "LabelAirsBeforeSeason": "Emitiranje prije sezone:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Izvođači albuma", - "LabelArtists": "Izvođači:", - "LabelArtistsHelp": "Odvoji višestruko koristeći ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Datum rođenja:", - "LabelBirthYear": "Godina rođenja:", - "LabelBitrateMbps": "Brzina prijenosa (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Kanali:", - "LabelCollection": "Kolekcija:", - "LabelCommunityRating": "Ocjene zajednice:", - "LabelContentType": "Tip sadržaja:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Zemlja:", - "LabelCriticRating": "Ocjene kritike:", - "LabelCustomRating": "Prilagođena ocjena:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Datumu dodavanja", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Datum smrti:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Poredak prikaza:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail adresa:", - "LabelEndDate": "Datum završetka:", - "LabelEpisodeNumber": "Broj epizode:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Ograničenje stavke:", - "LabelKeep:": "Zadrži:", - "LabelKeepUpTo": "Drži se na:", - "LabelLanguage": "Jezik:", - "LabelLockItemToPreventChanges": "Zaključajte ovu stavku kako bi se spriječile buduće promjene", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Željeni jezik za preuzimanje:", - "LabelName": "Ime:", - "LabelNumber": "Broj:", - "LabelOriginalAspectRatio": "Originalni omjer gledanja:", - "LabelOriginalTitle": "Originalni naslov:", - "LabelOverview": "Pregled:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Roditeljska ocjena:", - "LabelPath": "Putanja:", - "LabelPersonRole": "Uloga:", - "LabelPersonRoleHelp": "Primjer: vozač kamiona sa sladoledom", - "LabelPlaceOfBirth": "Datum rođenja:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Popis:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profil:", - "LabelQuality": "Kvaliteta:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Snimka:", - "LabelRefreshMode": "Način osvježavanja:", - "LabelReleaseDate": "Datum izdavanja:", - "LabelRuntimeMinutes": "Vrijeme izvođenja (minuta):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Broj sezone:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Kratki pregled:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Naziv vrste:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Počni kada je moguće:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Zaustavi kada je moguće:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Ime sinkronizacijskog posla:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sinkroniziraj na:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Slogan:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Naslov:", - "LabelTrackNumber": "Broj pjesme:", - "LabelType": "Tip:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Web stranica:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Nauči još", - "Like": "Sviđa mi se", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Uživo", - "LiveBroadcasts": "Emitiranja uživo", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Označi pogledan", - "MarkUnplayed": "Označi nepogledan", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Aktivna pretplata Jellyfin Premijere je potrebna kako bi se napravilo automatsko snimanje serija.", - "MessageAreYouSureDeleteSubtitles": "Da li ste sigurni da želite izbrisati ove titlove prijevoda?", - "MessageConfirmRecordingCancellation": "Jeste li sigurni da želite poništiti ovu snimku?", - "MessageDownloadQueued": "Preuzimanje na čekanju", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "Ako ste zabranili glasovni pristup aplikaciji morate ponovo podesiti prije ponovnog pokušaja.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Stavka je snimljena.", - "MessageItemsAdded": "Stavke su dodane", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Ostavite prazno da naslijedi postavke od roditelja stavke ili globalnu zadanu vrijednost.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "Ako imate aktivnu pretplatu Jellyfin Premijere provjerite dali ste postavili Jellyfin Premijeru u svojoj nadzornoj ploči Jellyfin Server-a kojoj možete pristupiti klikom Jellyfin Premijera u glavnom izborniku.", - "MessageUnlockAppWithPurchaseOrSupporter": "Otključaj ovu mogućnost s malom jednokratnom kupnjom ili s aktivnom pretplatom Jellyfin Premijere.", - "MessageUnlockAppWithSupporter": "Otključaj ovu mogućnost sa pretplatom Jellyfin Premijere.", - "MessageWeDidntRecognizeCommand": "Nažalost, nismo prepoznali tu naredbu.", - "MinutesAfter": "Minuta nakon", - "MinutesBefore": "Minuta prije", - "Mobile": "Mobile / Tablet", - "Monday": "Ponedjeljak", - "More": "More", - "MoveLeft": "Pomakni ulijevo", - "MoveRight": "Pomakni udesno", - "Movies": "Filmovi", - "MySubtitles": "Moji titlovi", - "Name": "Naziv", - "NewCollection": "Nova kolekcija", - "NewCollectionHelp": "Kolekcije vam omogućiti da napravite personalizirane grupe filmova i ostale biblioteke.", - "NewCollectionNameExample": "Naprimjer: Star Wars Kolekcija", - "NewEpisodes": "Nove epizode", - "NewEpisodesOnly": "Samo nove epizode", - "News": "Vijesti", - "Next": "Next", - "No": "No", - "NoItemsFound": "Nije ništa pronađeno.", - "NoSubtitleSearchResultsFound": "Nije ništa pronađeno.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Otvori", - "OptionNew": "Novo...", - "Original": "Original", - "OriginalAirDateValue": "Originalni datum prikazivanja: {0}", - "Overview": "Pregled", - "PackageInstallCancelled": "{0} instaliranje otkazano.", - "PackageInstallCompleted": "{0} instaliranje završeno.", - "PackageInstallFailed": "{0} instaliranje neuspjelo.", - "ParentalRating": "Parental Rating", - "People": "Ljudi", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Postavi omiljene kanale na početak", - "Play": "Pokreni", - "PlayAllFromHere": "Pokreni sve odavde", - "PlayCount": "Play count", - "PlayFromBeginning": "Igraj od početka", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Unesite naziv ili vanjski Id.", - "PleaseRestartServerName": "Ponovno pokrenite Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Molimo odaberite najmanje dvije stavke.", - "Premiere": "Premijera", - "Premieres": "Premijere", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producent", - "ProductionLocations": "Lokacije proizvodnje", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatski pretvoriti snimke na prijateljskom formatu strujanja s Jellyfin Premijerom. Snimke će se pretvoriti u letu u MP4 ili MKV na temelju postavki Jellyfin poslužitelja.", - "Quality": "Quality", - "QueueAllFromHere": "Stavi u red čekanja sve odavde", - "Raised": "Raised", - "RecentlyWatched": "Nedavno pogledano", - "Record": "Snimi", - "RecordSeries": "Snimi serije", - "RecordingCancelled": "Snimka je otkazana.", - "RecordingScheduled": "Snimka je zakazana.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Osviježi", - "RefreshDialogHelp": "Meta-podaci se osvježavaju na temelju postavki i internet usluga koje su omogućene u nadzornoj ploči Jellyfin Server-a.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Osviježi stavke na čekanju", - "Reject": "Reject", - "ReleaseDate": "Datum izdavanja", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Ukloni iz kolekcije", - "RemoveFromPlaylist": "Ukloni iz popisa", - "RemovingFromDevice": "Removing from device", - "Repeat": "Ponovi", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Reprize", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Zamijeni sve mate-podatke", - "ReplaceExistingImages": "Zamijeni postojeće slike", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Nastavi od {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Trajanje", - "Saturday": "Subota", - "Save": "Snimi", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Isječci slika", - "Search": "Traži", - "SearchForCollectionInternetMetadata": "Potraži na internetu grafike i metadata", - "SearchForMissingMetadata": "Potraga za meta-podacima koji nedostaju", - "SearchForSubtitles": "Traži titlove prijevoda", - "SearchResults": "Rezultati pretraživanja", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Serija je otkazana.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Snimanje serije je zakazano.", - "SeriesSettings": "Postavke serija", - "SeriesYearToPresent": "{0} - sada", - "ServerNameIsRestarting": "Jellyfin Server - {0} se ponovo pokreće.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} se gasi.", - "ServerUpdateNeeded": "Jellyfin Server treba ažurirati. Da biste preuzeli najnoviju verziju, posjetite {0}", - "Settings": "Postavke", - "SettingsSaved": "Settings saved.", - "Share": "Dijeli", - "ShowIndicatorsFor": "Prikaži pokazatelja za:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Miješaj", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Epizode će se usporediti pomoću sezone i broja epizode, kada su dostupni.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Složi kanale po:", - "SortName": "Ime vrste", - "Sports": "Sportovi", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studija", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Titlovi", - "Suggestions": "Suggestions", - "Sunday": "Nedjelja", - "Sync": "Sink.", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Oznake", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Molimo Vas da uživate u jednoj minuti reprodukcije. Hvala što ste isprobali Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Četvrtak", - "TrackCount": "{0} pjesme", - "Trailer": "Kratki video", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Pokušajte višestruki odabir", - "TryMultiSelectMessage": "Da biste uredili više medijskih stavaka, samo kliknite i držite bilo koji plakat i odaberite stavke kojima želite upravljati. Probaj!", - "Tuesday": "Utorak", - "Uniform": "Uniform", - "UnlockGuide": "Otključaj vodič", - "Unplayed": "Unplayed", - "Unrated": "Neocijenjeno", - "UntilIDelete": "Dok ne izbrišem", - "UntilSpaceNeeded": "Dok ne treba prostora", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albuma", - "ValueDiscNumber": "Disk {0}", - "ValueEpisodeCount": "{0} epizoda", - "ValueGameCount": "{0} igra", - "ValueMinutes": "{0} minuta", - "ValueMovieCount": "{0} filmova", - "ValueMusicVideoCount": "{0} glazbenih videa", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 epizoda", - "ValueOneGame": "1 igra", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 film", - "ValueOneMusicVideo": "1 glazbeni video", - "ValueOneSeries": "1 serija", - "ValueOneSong": "1 pjesma", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} serija", - "ValueSongCount": "{0} pjesma", - "ValueSpecialEpisodeName": "Specijal - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "Pogledaj album", - "ViewArtist": "Pogledaj umjetnika", - "VoiceInput": "Ulazni glas", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Srijeda", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Pisac", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "ServerUpdateNeeded": "Emby Server treba a\u017eurirati. Da biste preuzeli najnoviju verziju, posjetite {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "Novo", + "Premiere": "Premijera", + "Live": "U\u017eivo", + "Repeat": "Ponovi", + "TrackCount": "{0} pjesme", + "ItemCount": "{0} stavaka", + "OriginalAirDateValue": "Originalni datum prikazivanja: {0}", + "EndsAtValue": "Zavr\u0161ava u {0}", + "HeaderSelectDate": "Odaberi datum", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "U redu", + "ButtonCancel": "Odustani", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Shva\u0107am", + "ButtonRestart": "Ponovo pokreni", + "RecordingCancelled": "Snimka je otkazana.", + "SeriesCancelled": "Serija je otkazana.", + "RecordingScheduled": "Snimka je zakazana.", + "SeriesRecordingScheduled": "Snimanje serije je zakazano.", + "HeaderNewRecording": "Nova snimka", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Nedjelja", + "Monday": "Ponedjeljak", + "Tuesday": "Utorak", + "Wednesday": "Srijeda", + "Thursday": "\u010cetvrtak", + "Friday": "Petak", + "Saturday": "Subota", + "Days": "Dani", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Snimi serije", + "HeaderCinemaMode": "Kino na\u010din", + "HeaderCloudSync": "Sink. preko oblaka", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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 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", + "Record": "Snimi", + "Save": "Snimi", + "Edit": "Izmjeni", + "Download": "Preuzimanje", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Napredno", + "Delete": "Izbri\u0161i", + "HeaderDeleteItem": "Izbri\u0161i stavku", + "ConfirmDeleteItem": "Brisanjem ove stavke \u0107e je izbrisati iz oba datote\u010dnog sustava i medijskoj biblioteci. Jeste li sigurni da \u017eelite nastaviti?", + "Refresh": "Osvije\u017ei", + "RefreshQueued": "Osvije\u017ei stavke na \u010dekanju", + "AddToCollection": "Dodaj u kolekciju", + "HeaderAddToCollection": "Dodaj u kolekciju", + "NewCollection": "Nova kolekcija", + "LabelCollection": "Kolekcija:", + "Help": "Pomo\u0107", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Kolekcije vam omogu\u0107iti da napravite personalizirane grupe filmova i ostale biblioteke.", + "SearchForCollectionInternetMetadata": "Potra\u017ei na internetu grafike i metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Ime:", + "NewCollectionNameExample": "Naprimjer: Star Wars Kolekcija", + "MessageItemsAdded": "Stavke su dodane", + "OptionNew": "Novo...", + "LabelPlaylist": "Popis:", + "AddToPlaylist": "Dodaj u popis", + "HeaderAddToPlaylist": "Dodaj u popis", + "Subtitles": "Titlovi", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Tra\u017ei titlove prijevoda", + "LabelLanguage": "Jezik:", + "Search": "Tra\u017ei", + "NoSubtitleSearchResultsFound": "Nije ni\u0161ta prona\u0111eno.", + "File": "Datoteka", + "MessageAreYouSureDeleteSubtitles": "Da li ste sigurni da \u017eelite izbrisati ove titlove prijevoda?", + "ConfirmDeletion": "Potvrdite brisanje", + "MySubtitles": "Moji titlovi", + "MessageDownloadQueued": "Preuzimanje na \u010dekanju", + "EditSubtitles": "Uredi titlove", + "UnlockGuide": "Otklju\u010daj vodi\u010d", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Zamijeni postoje\u0107e slike", + "ReplaceAllMetadata": "Zamijeni sve mate-podatke", + "SearchForMissingMetadata": "Potraga za meta-podacima koji nedostaju", + "LabelRefreshMode": "Na\u010din osvje\u017eavanja:", + "NoItemsFound": "Nije ni\u0161ta prona\u0111eno.", + "HeaderSaySomethingLike": "Reci ne\u0161to poput...", + "ButtonTryAgain": "Poku\u0161ajte ponovo", + "HeaderYouSaid": "Rekao si...", + "MessageWeDidntRecognizeCommand": "Na\u017ealost, nismo prepoznali tu naredbu.", + "MessageIfYouBlockedVoice": "Ako ste zabranili glasovni pristup aplikaciji morate ponovo podesiti prije ponovnog poku\u0161aja.", + "ValueDiscNumber": "Disk {0}", + "Unrated": "Neocijenjeno", + "Favorite": "Omiljeni", + "Like": "Svi\u0111a mi se", + "Dislike": "Ne svi\u0111a mi se", + "RefreshDialogHelp": "Meta-podaci se osvje\u017eavaju na temelju postavki i internet usluga koje su omogu\u0107ene u nadzornoj plo\u010di Emby Server-a.", + "Open": "Otvori", + "Play": "Pokreni", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Mije\u0161aj", + "Identify": "Identificiraj", + "EditImages": "Ure\u0111ivanje slika", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sink.", + "InstantMix": "Trenutno mije\u0161anje", + "ViewAlbum": "Pogledaj album", + "ViewArtist": "Pogledaj umjetnika", + "QueueAllFromHere": "Stavi u red \u010dekanja sve odavde", + "PlayAllFromHere": "Pokreni sve odavde", + "PlayFromBeginning": "Igraj od po\u010detka", + "ResumeAt": "Nastavi od {0}", + "RemoveFromPlaylist": "Ukloni iz popisa", + "RemoveFromCollection": "Ukloni iz kolekcije", + "Sort": "Sort", + "Trailer": "Kratki video", + "MarkPlayed": "Ozna\u010di pogledan", + "MarkUnplayed": "Ozna\u010di nepogledan", + "GroupVersions": "Verzija grupe", + "PleaseSelectTwoItems": "Molimo odaberite najmanje dvije stavke.", + "TryMultiSelect": "Poku\u0161ajte vi\u0161estruki odabir", + "TryMultiSelectMessage": "Da biste uredili vi\u0161e medijskih stavaka, samo kliknite i dr\u017eite bilo koji plakat i odaberite stavke kojima \u017eelite upravljati. Probaj!", + "HeaderConfirmRecordingCancellation": "Potvrdi otkazivanje snimanja", + "MessageConfirmRecordingCancellation": "Jeste li sigurni da \u017eelite poni\u0161titi ovu snimku?", + "Error": "Gre\u0161ka", + "VoiceInput": "Ulazni glas", + "LabelContentType": "Tip sadr\u017eaja:", + "LabelPath": "Putanja:", + "Playlists": "Playlists", + "LabelTitle": "Naslov:", + "LabelOriginalTitle": "Originalni naslov:", + "LabelSortTitle": "Naziv vrste:", + "LabelDateAdded": "Datumu dodavanja", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Podesite kako se datum dodavanja odre\u0111uje na nadzornoj plo\u010di Emby Server-a u postavkama biblioteke", + "LabelStatus": "Status:", + "LabelArtists": "Izvo\u0111a\u010di:", + "LabelArtistsHelp": "Odvoji vi\u0161estruko koriste\u0107i ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Izvo\u0111a\u010di albuma", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Ocjene zajednice:", + "LabelCriticRating": "Ocjene kritike:", + "CriticRating": "Critic rating", + "LabelWebsite": "Web stranica:", + "LabelTagline": "Slogan:", + "LabelOverview": "Pregled:", + "LabelShortOverview": "Kratki pregled:", + "LabelReleaseDate": "Datum izdavanja:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Datum ro\u0111enja:", + "Aired": "Aired", + "LabelAirDays": "Dani emitiranja:", + "LabelAirTime": "Vrijeme emitiranja:", + "LabelRuntimeMinutes": "Vrijeme izvo\u0111enja (minuta):", + "LabelParentalRating": "Roditeljska ocjena:", + "LabelCustomRating": "Prilago\u0111ena ocjena:", + "LabelOriginalAspectRatio": "Originalni omjer gledanja:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Posebni podaci o epizodi", + "LabelAirsBeforeSeason": "Emitiranje prije sezone:", + "LabelAirsAfterSeason": "Emitiranje nakon sezona:", + "LabelAirsBeforeEpisode": "Emitiranje prije epizoda:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Postavke prikaza", + "LabelDisplayOrder": "Poredak prikaza:", + "Display": "Display", + "Countries": "Zemlje", + "Genres": "\u017danrovi", + "Studios": "Studija", + "Tags": "Oznake", + "HeaderMetadataSettings": "Postavke meta-podataka", + "People": "Ljudi", + "LabelMetadataDownloadLanguage": "\u017deljeni jezik za preuzimanje:", + "LabelLockItemToPreventChanges": "Zaklju\u010dajte ovu stavku kako bi se sprije\u010dile budu\u0107e promjene", + "MessageLeaveEmptyToInherit": "Ostavite prazno da naslijedi postavke od roditelja stavke ili globalnu zadanu vrijednost.", + "LabelCountry": "Zemlja:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Godina ro\u0111enja:", + "LabelBirthDate": "Datum ro\u0111enja:", + "LabelDeathDate": "Datum smrti:", + "LabelEndDate": "Datum zavr\u0161etka:", + "LabelSeasonNumber": "Broj sezone:", + "LabelEpisodeNumber": "Broj epizode:", + "LabelTrackNumber": "Broj pjesme:", + "LabelNumber": "Broj:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Ime vrste", + "ReleaseDate": "Datum izdavanja", + "Continuing": "Nastavlja se", + "Ended": "Zavr\u0161eno", + "HeaderEnabledFields": "Omogu\u0107i polja", + "HeaderEnabledFieldsHelp": "Poni\u0161ti polje za zaklju\u010davanje i sprije\u010di njihove podatke od toga da budu promijenjeni.", + "Backdrops": "Pozadine", + "Images": "Slike", + "Runtime": "Trajanje", + "ProductionLocations": "Lokacije proizvodnje", + "BirthLocation": "Lokacije ro\u0111enja", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Naziv", + "Overview": "Pregled", + "LabelType": "Tip:", + "LabelPersonRole": "Uloga:", + "LabelPersonRoleHelp": "Primjer: voza\u010d kamiona sa sladoledom", + "Actor": "Glumac", + "Composer": "Kompozitor", + "Director": "Re\u017eiser", + "GuestStar": "Zvijezda gost", + "Producer": "Producent", + "Writer": "Pisac", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Instaliranje {0}", + "PackageInstallCompleted": "{0} instaliranje zavr\u0161eno.", + "PackageInstallFailed": "{0} instaliranje neuspjelo.", + "PackageInstallCancelled": "{0} instaliranje otkazano.", + "SeriesYearToPresent": "{0} - sada", + "ValueOneItem": "1 item", + "ValueOneSong": "1 pjesma", + "ValueSongCount": "{0} pjesma", + "ValueOneMovie": "1 film", + "ValueMovieCount": "{0} filmova", + "ValueOneSeries": "1 serija", + "ValueSeriesCount": "{0} serija", + "ValueOneEpisode": "1 epizoda", + "ValueEpisodeCount": "{0} epizoda", + "ValueOneGame": "1 igra", + "ValueGameCount": "{0} igra", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albuma", + "ValueOneMusicVideo": "1 glazbeni video", + "ValueMusicVideoCount": "{0} glazbenih videa", + "ValueMinutes": "{0} minuta", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Unesite jednu ili vi\u0161e kriterija pretra\u017eivanja. Uklonite kriterije za pove\u0107anje rezultata pretra\u017eivanja.", + "PleaseEnterNameOrId": "Unesite naziv ili vanjski Id.", + "MessageItemSaved": "Stavka je snimljena.", + "SearchResults": "Rezultati pretra\u017eivanja", + "ServerNameIsRestarting": "Emby Server - {0} se ponovo pokre\u0107e.", + "ServerNameIsShuttingDown": "Emby Server - {0} se gasi.", + "HeaderDeleteItems": "Brisanje stavki", + "ConfirmDeleteItems": "Brisanjem ove stavke \u0107e se izbrisati iz oba datote\u010dnog sustava i medijskoj biblioteci. Jeste li sigurni da \u017eelite nastaviti?", + "PleaseRestartServerName": "Ponovno pokrenite Emby Server - {0}.", + "LabelSyncJobName": "Ime sinkronizacijskog posla:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Kvaliteta:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Nau\u010di jo\u0161", + "LabelProfile": "Profil:", + "LabelBitrateMbps": "Brzina prijenosa (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Ograni\u010denje stavke:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Isje\u010dci slika", + "MoveRight": "Pomakni udesno", + "MoveLeft": "Pomakni ulijevo", + "ConfirmDeleteImage": "Izbri\u0161i sliku?", + "HeaderEditImages": "Ure\u0111ivanje slika", + "Settings": "Postavke", + "ShowIndicatorsFor": "Prika\u017ei pokazatelja za:", + "NewEpisodes": "Nove epizode", + "Episodes": "Episodes", + "HDPrograms": "HD programi", + "Programs": "Programs", + "LiveBroadcasts": "Emitiranja u\u017eivo", + "Premieres": "Premijere", + "RepeatEpisodes": "Reprize", + "DvrSubscriptionRequired": "Emby DVR zahtijeva aktivnu pretplatu Emby Premijere.", + "HeaderCancelRecording": "Prekini snimanje", + "CancelRecording": "Prekini snimanje", + "HeaderKeepRecording": "Zadr\u017ei snimanje", + "HeaderCancelSeries": "Otka\u017ei serije", + "HeaderKeepSeries": "Zadr\u017ei serije", + "HeaderLearnMore": "Nau\u010di jo\u0161", + "DeleteMedia": "Izbri\u0161i medij", + "SeriesSettings": "Postavke serija", + "HeaderRecordingOptions": "Opcije snimanja", + "CancelSeries": "Odustani od serije", + "DoNotRecord": "Ne snimi", + "HeaderSeriesOptions": "Opcije serija", + "LabelChannels": "Kanali:", + "ChannelNameOnly": "Kanali {0} samo", + "Anytime": "Bilo kada", + "AnyLanguage": "Any language", + "AroundTime": "Oko {0}", + "All": "All", + "AllChannels": "Svi kanali", + "LabelRecord": "Snimka:", + "NewEpisodesOnly": "Samo nove epizode", + "AllEpisodes": "Sve epizode", + "LabelStartWhenPossible": "Po\u010dni kada je mogu\u0107e:", + "LabelStopWhenPossible": "Zaustavi kada je mogu\u0107e:", + "MinutesBefore": "Minuta prije", + "MinutesAfter": "Minuta nakon", + "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", + "SkipEpisodesAlreadyInMyLibraryHelp": "Epizode \u0107e se usporediti pomo\u0107u sezone i broja epizode, kada su dostupni.", + "LabelKeepUpTo": "Dr\u017ei se na:", + "AsManyAsPossible": "\u0160to vi\u0161e je mogu\u0107e", + "DefaultErrorMessage": "Do\u0161lo je do pogre\u0161ke prilikom obrade zahtjeva. Molimo poku\u0161ajte ponovo kasnije.", + "LabelKeep:": "Zadr\u017ei:", + "UntilIDelete": "Dok ne izbri\u0161em", + "UntilSpaceNeeded": "Dok ne treba prostora", + "Categories": "Kategorije", + "Sports": "Sportovi", + "News": "Vijesti", + "Movies": "Filmovi", + "Kids": "Djeca", + "EnableColorCodedBackgrounds": "Omogu\u0107i kodirane boje pozadine", + "SortChannelsBy": "Slo\u017ei kanale po:", + "RecentlyWatched": "Nedavno pogledano", + "ChannelNumber": "Broj kanala", + "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": "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sinkroniziraj na:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/hu.json b/src/bower_components/emby-webcomponents/strings/hu.json index a8155814b2..de782de884 100644 --- a/src/bower_components/emby-webcomponents/strings/hu.json +++ b/src/bower_components/emby-webcomponents/strings/hu.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Hozzáad", - "AddToCollection": "Hozzáadás gyűjteményhez", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Lejátszási listához adni", - "AddedOnValue": "Hozzáadva {0}", - "Advanced": "Haladó", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Összes epizód", - "AllLanguages": "Összes nyelv", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Növekvő", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "A kiszolgáló felébresztése folyamatban. Kérlek várj...", - "AttributeNew": "Új", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audió profil nem támogatott", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Automatikus (a nyelvi beállítások alapján)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Könyvek", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Mégsem", - "ButtonGotIt": "Értettem", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Egy perc lejátszása", - "ButtonRestart": "Újraindítás", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "A Cinema Mode igazi mozi élményt nyújt előzetessel és egyedi intróval a film vetítése előtt.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Gyűjtemények", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Közösségi értékelés", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Kapcsolódás", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Tovább", - "ContinueInSecondsValue": "Tovább {0} mp múlva.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Átkonvertál", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Csak a nem látott videók konvertálása", - "ConvertUnwatchedVideosOnlyHelp": "Csak a nem látott videók lesznek konvertálva.", - "ConvertingDots": "Átkonvertálás...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Hozzáadva", - "DatePlayed": "Lejátszás dátuma", - "Days": "Nap", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Törlés", - "DeleteMedia": "Média törlés", - "Depressed": "Depressed", - "Descending": "Csökkenő", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Rendező", - "DirectorValue": "Rendező: {0}", - "DirectorsValue": "Rendezők: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Nem tettszik", - "Display": "Megjelenítés", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Hiányzó évad epizódok megjelenítése", - "DisplayMissingEpisodesWithinSeasonsHelp": "Ezt engedélyezni kell az Jellyfin Szerver beállításban lévő TV könyvtárak esetében is.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Le", - "Download": "Letöltés", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Letöltött", - "Downloading": "Letöltés", - "DownloadingDots": "Letöltés...", - "Downloads": "Letöltések", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Szerkesztés", - "EditImages": "Képek szerkesztése", - "EditMetadata": "Metaadat szerkesztés", - "EditSubtitles": "Feliratok szerkesztése", - "EnableBackdrops": "Háttérképek engedélyezve", - "EnableBackdropsHelp": "Ha engedélyezve van, akkor a háttérképek a könyvtár böngészése közben néhány oldal hátterében jelennek meg.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Főcím dalok engedélyezése", - "EnableThemeSongsHelp": "Ha engedélyezve van, a főcím dalok a háttérben játszódnak le a könyvtár böngészése közben.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Várható befejezés {0}", - "Episodes": "Epizódok", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Kedvenc", - "Favorites": "Kedvencek", - "FeatureRequiresJellyfinPremiere": "Ez a szolgáltatás aktív Jellyfin Premier előfizetést igényel.", - "Features": "Jellemzők", - "File": "File", - "Fill": "Fill", - "Filters": "Szűrők", - "Folders": "Mappák", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Péntek", - "GenreValue": "Genre: {0}", - "Genres": "Műfajok", - "GenresValue": "Műfajok: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Hozzáadás gyűjteményhez", - "HeaderAddToPlaylist": "Lejátszási listához adni", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Már Fizetve?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Hangos könyvek", - "HeaderAudioSettings": "Audió Beállítások", - "HeaderBecomeProjectSupporter": "Jellyfin Premiere beszerzése", - "HeaderBenefitsJellyfinPremiere": "Jellyfin Premiere előnyei", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Felhőszinkronizáció ", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Vetítés(ek) folytatása", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Kezdőképernyő testreszabása", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Képernyő beállítások", - "HeaderDownloadSettings": "Letöltés beállítások", - "HeaderEditImages": "Képek szerkesztése", - "HeaderEnabledFields": "Engedélyezett mezők", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "Külső id-k:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Kedvenc Epizódok", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Kedvenc Filmek", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Kedvenc Műsorok", - "HeaderFavoriteSongs": "Kedvenc Dalok", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Ingyenes Jellyfin alkalmazások", - "HeaderHomeScreen": "Kezdőképernyő", - "HeaderIdentifyItemHelp": "Adj meg egy vagy több keresési kritériumot. Távolítsd el a kritériumokat a keresési eredmények növelése érdekében.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Legújabb innen {0}", - "HeaderLatestMedia": "Legújabb média", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Könyvtár mappák", - "HeaderLibraryOrder": "Médiatár rendezés", - "HeaderMetadataSettings": "Metaadat Beállítások", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "Jelenlegi eszköz", - "HeaderMyDownloads": "Letöltések", - "HeaderMyMedia": "Médiatáram", - "HeaderMyMediaSmall": "Médiatáram (kicsi)", - "HeaderNewRecording": "Új Felvétel", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Következik", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Média", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Vetítés itt", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Válassz dátumot", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Felirat Beállítások", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Funkció feloldása", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Videó típusa:", - "HeaderWaitingForWifi": "Wifi-re vár", - "HeaderWakeServer": "Kiszolgáló felébresztés", - "HeaderYouSaid": "You Said...", - "Help": "Segítség", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "A megtekintett tartalom elrejtése a legújabb médiából", - "Home": "Kezdőlap", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Azonosítás", - "Images": "Képek", - "ImdbRating": "IMDb rating", - "InstallingPackage": "{0} Telepítése", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D formátum:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Előadók:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audió:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Születési év:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Gyűjtemény:", - "LabelCommunityRating": "Közösségi értékelés:", - "LabelContentType": "Tartalom típusa:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Ország:", - "LabelCriticRating": "Kritikusok értékelése", - "LabelCustomRating": "Egyéni értékelés:", - "LabelDashboardTheme": "Szerver vezérlőpult kinézet:", - "LabelDateAdded": "Hozzáadva:", - "LabelDateTimeLocale": "Földrajzi dátum:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Megjelenítési sorrend:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail cím:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Epizód száma:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Kezdőképernyő blokk {0}:", - "LabelImageType": "Kép típusa:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Elemszám limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Nyelv:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Elsődleges letöltendő nyelv:", - "LabelName": "Név:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Eredeti képarány:", - "LabelOriginalTitle": "Eredeti cím:", - "LabelOverview": "Tartalom:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Korhatár besorolás:", - "LabelPath": "Útvonal:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Lejátszási lista:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profil:", - "LabelQuality": "Minőség:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Frissítési mód:", - "LabelReleaseDate": "Megjelenés dátuma:", - "LabelRuntimeMinutes": "Játékidő (perc):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Évad száma:", - "LabelSelectFolderGroups": "Automatikusan csoportosítsa a következő mappák tartalmát olyan nézetekre, mint a Filmek, a Zene és a TV:", - "LabelSelectFolderGroupsHelp": "A ki nem választott mappák önmagukban, saját nézetben jelennek meg.", - "LabelShortOverview": "Rövid tartalom:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Rendezés:", - "LabelSortOrder": "Sorrend:", - "LabelSortTitle": "ABC szerinti cím:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Forrás:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Státusz:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Feliratok:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Címke:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Kinézet:", - "LabelTitle": "Cím:", - "LabelTrackNumber": "Track number:", - "LabelType": "Típus:", - "LabelVersion": "Version:", - "LabelVideo": "Videó:", - "LabelWebsite": "Weboldal:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Év:", - "Large": "Large", - "LatestFromLibrary": "Legújabb {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Tettszik", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Élő", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "A Live TV aktív Jellyfin Premiere előfizetést igényel.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Megtekintett", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Engedélyezd ezt a funkciót aktív Jellyfin Premiere előfizetéssel.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Hétfő", - "More": "Tovább", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Filmek", - "MySubtitles": "Feliratok", - "Name": "Név", - "NewCollection": "Új Gyűjtemény", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Például: Star Wars Gyűjtemény", - "NewEpisodes": "Új epizódok", - "NewEpisodesOnly": "Csak új epizódok", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "Nincs találat.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "Nincs", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Megnyitás", - "OptionNew": "Új...", - "Original": "Original", - "OriginalAirDateValue": "Eredeti vetítés dátuma: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} telepítése megszakítva.", - "PackageInstallCompleted": "{0} telepítése befejezve.", - "PackageInstallFailed": "{0} telepítése nem sikerült.", - "ParentalRating": "Korhatár besorolás", - "People": "Személyek", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Lejátszás", - "PlayAllFromHere": "Összes vetítése innen", - "PlayCount": "Lejátszások száma", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Megnézett", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Kérlek indítsd újra az Jellyfin Szerver-t - {0}.", - "PleaseSelectDeviceToSyncTo": "Válassz egy eszközt a letöltéshez.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Minőség", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Felvétel", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Frissítés", - "RefreshDialogHelp": "A metaadatok frissítése az Jellyfin Server vezérlőpultjában engedélyezett beállítások és internetszolgáltatások alapján történik.", - "RefreshMetadata": "Metaadat frissítés", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Megjelenés dátuma", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Ismétlés", - "RepeatAll": "Folyamatos ismétlés ", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Ismétlő mód", - "RepeatOne": "Ismétlés egyszer", - "ReplaceAllMetadata": "Összes metaadat cseréje", - "ReplaceExistingImages": "Cserélje ki a meglévő képeket", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Játékidő", - "Saturday": "Szombat", - "Save": "Mentés", - "ScanForNewAndUpdatedFiles": "Keresés az új és frissített fileokra", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Keresés", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Keresés a hiányzó metaadatokra", - "SearchForSubtitles": "Felirat keresése", - "SearchResults": "A keresés eredménye", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Napjainkig", - "ServerNameIsRestarting": "Jellyfin Szerver - {0} újraindul.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} leáll.", - "ServerUpdateNeeded": "Ezt az Jellyfin Sertvert frissíteni kell. A legújabb verzió letöltéséhez kérjük, látogass el ide {0}", - "Settings": "Beállítások", - "SettingsSaved": "Settings saved.", - "Share": "Megosztás", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Név megjelenítése", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Keverés", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Az epizódokat összehasonlítjuk az évad és az epizód számával, ha rendelkezésre állnak.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Rendezés: ", - "SortByValue": "Rendezés {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Szakértői statisztika", - "StopRecording": "Stop recording", - "Studios": "Stúdiók", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Feliratok", - "Suggestions": "Javaslatok", - "Sunday": "Vasárnap", - "Sync": "Szinkronizál", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Átkonvertálás", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Címkék", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Csütörtök", - "TrackCount": "{0} tracks", - "Trailer": "Előzetes", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Kedd", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Fel", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} epizód", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} film", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Videó profil nem támogatott", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Kiszolgáló felébresztés", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Megtekintett", - "Wednesday": "Szerda", - "WifiRequiredToDownload": "Wifi kapcsolat szükséges a letöltés folytatásához.", - "Writer": "Író", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Emby Premiere subscription.", + "MessageUnlockAppWithSupporter": "Enged\u00e9lyezd ezt a funkci\u00f3t akt\u00edv Emby Premiere el\u0151fizet\u00e9ssel.", + "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": "Megoszt\u00e1s", + "Add": "Hozz\u00e1ad", + "ServerUpdateNeeded": "Ezt az Emby Sertvert friss\u00edteni kell. A leg\u00fajabb verzi\u00f3 let\u00f6lt\u00e9s\u00e9hez k\u00e9rj\u00fck, l\u00e1togass el ide {0}", + "LiveTvRequiresUnlock": "A Live TV akt\u00edv Emby Premiere el\u0151fizet\u00e9st ig\u00e9nyel.", + "AttributeNew": "\u00daj", + "Premiere": "Premiere", + "Live": "\u00c9l\u0151", + "Repeat": "Ism\u00e9tl\u00e9s", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Eredeti vet\u00edt\u00e9s d\u00e1tuma: {0}", + "EndsAtValue": "V\u00e1rhat\u00f3 befejez\u00e9s {0}", + "HeaderSelectDate": "V\u00e1lassz d\u00e1tumot", + "Watched": "Megtekintett", + "AirDate": "Air date", + "Played": "Megn\u00e9zett", + "ButtonOk": "Ok", + "ButtonCancel": "M\u00e9gsem", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "\u00c9rtettem", + "ButtonRestart": "\u00dajraind\u00edt\u00e1s", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "\u00daj Felv\u00e9tel", + "WakeServer": "Kiszolg\u00e1l\u00f3 fel\u00e9breszt\u00e9s", + "HeaderWakeServer": "Kiszolg\u00e1l\u00f3 fel\u00e9breszt\u00e9s", + "AttemptingWakeServer": "A kiszolg\u00e1l\u00f3 fel\u00e9breszt\u00e9se folyamatban. K\u00e9rlek v\u00e1rj...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Kezd\u0151k\u00e9perny\u0151 testreszab\u00e1sa", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Vas\u00e1rnap", + "Monday": "H\u00e9tf\u0151", + "Tuesday": "Kedd", + "Wednesday": "Szerda", + "Thursday": "Cs\u00fct\u00f6rt\u00f6k", + "Friday": "P\u00e9ntek", + "Saturday": "Szombat", + "Days": "Nap", + "SortByValue": "Rendez\u00e9s {0}", + "LabelSortBy": "Rendez\u00e9s:", + "LabelSortOrder": "Sorrend:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Felh\u0151szinkroniz\u00e1ci\u00f3 ", + "Downloads": "Let\u00f6lt\u00e9sek", + "HeaderMyDownloads": "Let\u00f6lt\u00e9sek", + "HeaderOfflineDownloads": "Offline M\u00e9dia", + "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", + "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "CinemaModeFeatureDescription": "A Cinema Mode igazi mozi \u00e9lm\u00e9nyt ny\u00fajt el\u0151zetessel \u00e9s egyedi intr\u00f3val a film vet\u00edt\u00e9se el\u0151tt.", + "HeaderFreeApps": "Ingyenes Emby alkalmaz\u00e1sok", + "FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.", + "HeaderBecomeProjectSupporter": "Emby Premiere beszerz\u00e9se", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "LabelEmailAddress": "E-mail c\u00edm:", + "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": "Ez a szolg\u00e1ltat\u00e1s akt\u00edv Emby Premier el\u0151fizet\u00e9st ig\u00e9nyel.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Felv\u00e9tel", + "Save": "Ment\u00e9s", + "Edit": "Szerkeszt\u00e9s", + "Download": "Let\u00f6lt\u00e9s", + "Downloaded": "Let\u00f6lt\u00f6tt", + "Downloading": "Let\u00f6lt\u00e9s", + "Advanced": "Halad\u00f3", + "Delete": "T\u00f6rl\u00e9s", + "HeaderDeleteItem": "Delete Item", + "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", + "Refresh": "Friss\u00edt\u00e9s", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Hozz\u00e1ad\u00e1s gy\u0171jtem\u00e9nyhez", + "HeaderAddToCollection": "Hozz\u00e1ad\u00e1s gy\u0171jtem\u00e9nyhez", + "NewCollection": "\u00daj Gy\u0171jtem\u00e9ny", + "LabelCollection": "Gy\u0171jtem\u00e9ny:", + "Help": "Seg\u00edts\u00e9g", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Hi\u00e1nyz\u00f3 \u00e9vad epiz\u00f3dok megjelen\u00edt\u00e9se", + "DisplayMissingEpisodesWithinSeasonsHelp": "Ezt enged\u00e9lyezni kell az Emby Szerver be\u00e1ll\u00edt\u00e1sban l\u00e9v\u0151 TV k\u00f6nyvt\u00e1rak eset\u00e9ben is.", + "EnableThemeSongs": "F\u0151c\u00edm dalok enged\u00e9lyez\u00e9se", + "EnableBackdrops": "H\u00e1tt\u00e9rk\u00e9pek enged\u00e9lyezve", + "EnableThemeSongsHelp": "Ha enged\u00e9lyezve van, a f\u0151c\u00edm dalok a h\u00e1tt\u00e9rben j\u00e1tsz\u00f3dnak le a k\u00f6nyvt\u00e1r b\u00f6ng\u00e9sz\u00e9se k\u00f6zben.", + "EnableBackdropsHelp": "Ha enged\u00e9lyezve van, akkor a h\u00e1tt\u00e9rk\u00e9pek a k\u00f6nyvt\u00e1r b\u00f6ng\u00e9sz\u00e9se k\u00f6zben n\u00e9h\u00e1ny oldal h\u00e1tter\u00e9ben jelennek meg.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "N\u00e9v:", + "NewCollectionNameExample": "P\u00e9ld\u00e1ul: Star Wars Gy\u0171jtem\u00e9ny", + "MessageItemsAdded": "Items added.", + "OptionNew": "\u00daj...", + "LabelPlaylist": "Lej\u00e1tsz\u00e1si lista:", + "AddToPlaylist": "Lej\u00e1tsz\u00e1si list\u00e1hoz adni", + "HeaderAddToPlaylist": "Lej\u00e1tsz\u00e1si list\u00e1hoz adni", + "Subtitles": "Feliratok", + "LabelTheme": "Kin\u00e9zet:", + "LabelDashboardTheme": "Szerver vez\u00e9rl\u0151pult kin\u00e9zet:", + "SearchForSubtitles": "Felirat keres\u00e9se", + "LabelLanguage": "Nyelv:", + "Search": "Keres\u00e9s", + "NoSubtitleSearchResultsFound": "Nincs tal\u00e1lat.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "Feliratok", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Feliratok szerkeszt\u00e9se", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Metaadat friss\u00edt\u00e9s", + "ReplaceExistingImages": "Cser\u00e9lje ki a megl\u00e9v\u0151 k\u00e9peket", + "ReplaceAllMetadata": "\u00d6sszes metaadat cser\u00e9je", + "SearchForMissingMetadata": "Keres\u00e9s a hi\u00e1nyz\u00f3 metaadatokra", + "LabelRefreshMode": "Friss\u00edt\u00e9si m\u00f3d:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Kedvenc", + "Like": "Tettszik", + "Dislike": "Nem tettszik", + "RefreshDialogHelp": "A metaadatok friss\u00edt\u00e9se az Emby Server vez\u00e9rl\u0151pultj\u00e1ban enged\u00e9lyezett be\u00e1ll\u00edt\u00e1sok \u00e9s internetszolg\u00e1ltat\u00e1sok alapj\u00e1n t\u00f6rt\u00e9nik.", + "Open": "Megnyit\u00e1s", + "Play": "Lej\u00e1tsz\u00e1s", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Kever\u00e9s", + "Identify": "Azonos\u00edt\u00e1s", + "EditImages": "K\u00e9pek szerkeszt\u00e9se", + "EditMetadata": "Metaadat szerkeszt\u00e9s", + "Convert": "\u00c1tkonvert\u00e1l", + "Sync": "Szinkroniz\u00e1l", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "\u00d6sszes vet\u00edt\u00e9se innen", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Rendez\u00e9s: ", + "Trailer": "El\u0151zetes", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Tartalom t\u00edpusa:", + "LabelPath": "\u00datvonal:", + "Playlists": "Playlists", + "LabelTitle": "C\u00edm:", + "LabelOriginalTitle": "Eredeti c\u00edm:", + "LabelSortTitle": "ABC szerinti c\u00edm:", + "LabelDateAdded": "Hozz\u00e1adva:", + "DateAdded": "Hozz\u00e1adva", + "DatePlayed": "Lej\u00e1tsz\u00e1s d\u00e1tuma", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "St\u00e1tusz:", + "LabelArtists": "El\u0151ad\u00f3k:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "K\u00f6z\u00f6ss\u00e9gi \u00e9rt\u00e9kel\u00e9s", + "LabelCommunityRating": "K\u00f6z\u00f6ss\u00e9gi \u00e9rt\u00e9kel\u00e9s:", + "LabelCriticRating": "Kritikusok \u00e9rt\u00e9kel\u00e9se", + "CriticRating": "Critic rating", + "LabelWebsite": "Weboldal:", + "LabelTagline": "C\u00edmke:", + "LabelOverview": "Tartalom:", + "LabelShortOverview": "R\u00f6vid tartalom:", + "LabelReleaseDate": "Megjelen\u00e9s d\u00e1tuma:", + "LabelYear": "\u00c9v:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "J\u00e1t\u00e9kid\u0151 (perc):", + "LabelParentalRating": "Korhat\u00e1r besorol\u00e1s:", + "LabelCustomRating": "Egy\u00e9ni \u00e9rt\u00e9kel\u00e9s:", + "LabelOriginalAspectRatio": "Eredeti k\u00e9par\u00e1ny:", + "Label3DFormat": "3D form\u00e1tum:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "K\u00fcls\u0151 id-k:", + "HeaderDisplaySettings": "K\u00e9perny\u0151 be\u00e1ll\u00edt\u00e1sok", + "LabelDisplayOrder": "Megjelen\u00edt\u00e9si sorrend:", + "Display": "Megjelen\u00edt\u00e9s", + "Countries": "Countries", + "Genres": "M\u0171fajok", + "Studios": "St\u00fadi\u00f3k", + "Tags": "C\u00edmk\u00e9k", + "HeaderMetadataSettings": "Metaadat Be\u00e1ll\u00edt\u00e1sok", + "People": "Szem\u00e9lyek", + "LabelMetadataDownloadLanguage": "Els\u0151dleges let\u00f6ltend\u0151 nyelv:", + "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", + "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", + "LabelCountry": "Orsz\u00e1g:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Sz\u00fclet\u00e9si \u00e9v:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "\u00c9vad sz\u00e1ma:", + "LabelEpisodeNumber": "Epiz\u00f3d sz\u00e1ma:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Megjelen\u00e9s d\u00e1tuma", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enged\u00e9lyezett mez\u0151k", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "K\u00e9pek", + "Runtime": "J\u00e1t\u00e9kid\u0151", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Korhat\u00e1r besorol\u00e1s", + "PlayCount": "Lej\u00e1tsz\u00e1sok sz\u00e1ma", + "Name": "N\u00e9v", + "Overview": "Overview", + "LabelType": "T\u00edpus:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Rendez\u0151", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "\u00cdr\u00f3", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "{0} Telep\u00edt\u00e9se", + "PackageInstallCompleted": "{0} telep\u00edt\u00e9se befejezve.", + "PackageInstallFailed": "{0} telep\u00edt\u00e9se nem siker\u00fclt.", + "PackageInstallCancelled": "{0} telep\u00edt\u00e9se megszak\u00edtva.", + "SeriesYearToPresent": "{0} - Napjainkig", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} film", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} epiz\u00f3d", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "K\u00f6nyvek", + "HeaderAudioBooks": "Hangos k\u00f6nyvek", + "HeaderIdentifyItemHelp": "Adj meg egy vagy t\u00f6bb keres\u00e9si krit\u00e9riumot. T\u00e1vol\u00edtsd el a krit\u00e9riumokat a keres\u00e9si eredm\u00e9nyek n\u00f6vel\u00e9se \u00e9rdek\u00e9ben.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "A keres\u00e9s eredm\u00e9nye", + "ServerNameIsRestarting": "Emby Szerver - {0} \u00fajraindul.", + "ServerNameIsShuttingDown": "Emby Server - {0} le\u00e1ll.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "K\u00e9rlek ind\u00edtsd \u00fajra az Emby Szerver-t - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "\u00c1tkonvert\u00e1l\u00e1s...", + "LabelQuality": "Min\u0151s\u00e9g:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Let\u00f6lt\u00e9s...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profil:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Csak a nem l\u00e1tott vide\u00f3k konvert\u00e1l\u00e1sa", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Csak a nem l\u00e1tott vide\u00f3k lesznek konvert\u00e1lva.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Elemsz\u00e1m limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "V\u00e1lassz egy eszk\u00f6zt a let\u00f6lt\u00e9shez.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "K\u00e9pek szerkeszt\u00e9se", + "Settings": "Be\u00e1ll\u00edt\u00e1sok", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "\u00daj epiz\u00f3dok", + "Episodes": "Epiz\u00f3dok", + "HDPrograms": "HD programs", + "Programs": "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": "M\u00e9dia t\u00f6rl\u00e9s", + "SeriesSettings": "Series settings", + "HeaderRecordingOptions": "Recording Options", + "CancelSeries": "Cancel series", + "DoNotRecord": "Do not record", + "HeaderSeriesOptions": "Series Options", + "LabelChannels": "Channels:", + "ChannelNameOnly": "Channel {0} only", + "Anytime": "Anytime", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "AllChannels": "All channels", + "LabelRecord": "Record:", + "NewEpisodesOnly": "Csak \u00faj epiz\u00f3dok", + "AllEpisodes": "\u00d6sszes epiz\u00f3d", + "LabelStartWhenPossible": "Start when possible:", + "LabelStopWhenPossible": "Stop when possible:", + "MinutesBefore": "minutes before", + "MinutesAfter": "minutes after", + "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", + "SkipEpisodesAlreadyInMyLibraryHelp": "Az epiz\u00f3dokat \u00f6sszehasonl\u00edtjuk az \u00e9vad \u00e9s az epiz\u00f3d sz\u00e1m\u00e1val, ha rendelkez\u00e9sre \u00e1llnak.", + "LabelKeepUpTo": "Keep up to:", + "AsManyAsPossible": "As many as possible", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "LabelKeep:": "Keep:", + "UntilIDelete": "Until I delete", + "UntilSpaceNeeded": "Until space needed", + "Categories": "Categories", + "Sports": "Sports", + "News": "News", + "Movies": "Filmek", + "Kids": "Kids", + "EnableColorCodedBackgrounds": "Enable color coded backgrounds", + "SortChannelsBy": "Sort channels by:", + "RecentlyWatched": "Recently watched", + "ChannelNumber": "Channel number", + "HeaderBenefitsEmbyPremiere": "Emby Premiere el\u0151nyei", + "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}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}", + "HeaderAlreadyPaid": "M\u00e1r Fizetve?", + "ButtonPlayOneMinute": "Egy perc lej\u00e1tsz\u00e1sa", + "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", + "HeaderUnlockFeature": "Funkci\u00f3 felold\u00e1sa", + "MessageDidYouKnowCinemaMode": "Tudtad, hogy az Emby Premiere-t haszn\u00e1lva olyan funkci\u00f3kkal fokozhatod az \u00e9lm\u00e9nyeket, mint a Cinema Mode?", + "MessageDidYouKnowCinemaMode2": "A Cinema Mode igazi mozi \u00e9lm\u00e9nyt ny\u00fajt el\u0151zetessel \u00e9s egyedi intr\u00f3val a film vet\u00edt\u00e9se el\u0151tt.", + "HeaderPlayMyMedia": "Play my Media", + "HeaderDiscoverEmbyPremiere": "Fedezd fel az Emby Premiere-t", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Hozz\u00e1adva {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "\u00c1tkonvert\u00e1l\u00e1s", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "Jelenlegi eszk\u00f6z", + "Continue": "Tov\u00e1bb", + "ContinueInSecondsValue": "Tov\u00e1bb {0} mp m\u00falva.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Vet\u00edt\u00e9s itt", + "Quality": "Min\u0151s\u00e9g", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Kapcsol\u00f3d\u00e1s", + "HeaderMyMedia": "M\u00e9diat\u00e1ram", + "HeaderMyMediaSmall": "M\u00e9diat\u00e1ram (kicsi)", + "LatestFromLibrary": "Leg\u00fajabb {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Vet\u00edt\u00e9s(ek) folytat\u00e1sa", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Forr\u00e1s:", + "LabelVersion": "Version:", + "AllLanguages": "\u00d6sszes nyelv", + "Previous": "Previous", + "HeaderNextUp": "K\u00f6vetkezik", + "HeaderLatestFrom": "Leg\u00fajabb innen {0}", + "LabelHomeScreenSectionValue": "Kezd\u0151k\u00e9perny\u0151 blokk {0}:", + "SettingsSaved": "Settings saved.", + "None": "Nincs", + "More": "Tov\u00e1bb", + "Up": "Fel", + "Down": "Le", + "Home": "Kezd\u0151lap", + "Favorites": "Kedvencek", + "HeaderHomeScreen": "Kezd\u0151k\u00e9perny\u0151", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "M\u00e9diat\u00e1r rendez\u00e9s", + "HideWatchedContentFromLatestMedia": "A megtekintett tartalom elrejt\u00e9se a leg\u00fajabb m\u00e9di\u00e1b\u00f3l", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Javaslatok", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Gy\u0171jtem\u00e9nyek", + "LabelSelectFolderGroups": "Automatikusan csoportos\u00edtsa a k\u00f6vetkez\u0151 mapp\u00e1k tartalm\u00e1t olyan n\u00e9zetekre, mint a Filmek, a Zene \u00e9s a TV:", + "LabelSelectFolderGroupsHelp": "A ki nem v\u00e1lasztott mapp\u00e1k \u00f6nmagukban, saj\u00e1t n\u00e9zetben jelennek meg.", + "Folders": "Mapp\u00e1k", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "K\u00f6nyvt\u00e1r mapp\u00e1k", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Ism\u00e9tl\u0151 m\u00f3d", + "RepeatOne": "Ism\u00e9tl\u00e9s egyszer", + "RepeatAll": "Folyamatos ism\u00e9tl\u00e9s ", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Megtekintett", + "ScanForNewAndUpdatedFiles": "Keres\u00e9s az \u00faj \u00e9s friss\u00edtett fileokra", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Szak\u00e9rt\u0151i statisztika", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audi\u00f3 profil nem t\u00e1mogatott", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Felirat Be\u00e1ll\u00edt\u00e1sok", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Wifi-re v\u00e1r", + "WifiRequiredToDownload": "Wifi kapcsolat sz\u00fcks\u00e9ges a let\u00f6lt\u00e9s folytat\u00e1s\u00e1hoz.", + "HeaderDownloadSettings": "Let\u00f6lt\u00e9s be\u00e1ll\u00edt\u00e1sok", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Vide\u00f3 profil nem t\u00e1mogatott", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "K\u00e9p t\u00edpusa:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audi\u00f3 Be\u00e1ll\u00edt\u00e1sok", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Leg\u00fajabb m\u00e9dia", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Automatikus (a nyelvi be\u00e1ll\u00edt\u00e1sok alapj\u00e1n)", + "LabelDateTimeLocale": "F\u00f6ldrajzi d\u00e1tum:", + "DirectorValue": "Rendez\u0151: {0}", + "DirectorsValue": "Rendez\u0151k: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "M\u0171fajok: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audi\u00f3:", + "LabelVideo": "Vide\u00f3:", + "LabelSubtitles": "Feliratok:", + "Off": "Off", + "ShowTitle": "N\u00e9v megjelen\u00edt\u00e9se", + "ShowYear": "Show year", + "Filters": "Sz\u0171r\u0151k", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Vide\u00f3 t\u00edpusa:", + "HeaderSeriesStatus": "Series Status", + "Features": "Jellemz\u0151k", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Kedvenc Filmek", + "HeaderFavoriteShows": "Kedvenc M\u0171sorok", + "HeaderFavoriteEpisodes": "Kedvenc Epiz\u00f3dok", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Kedvenc Dalok", + "Ascending": "N\u00f6vekv\u0151", + "Descending": "Cs\u00f6kken\u0151", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/id.json b/src/bower_components/emby-webcomponents/strings/id.json index 63bb57ab91..27492b5bef 100644 --- a/src/bower_components/emby-webcomponents/strings/id.json +++ b/src/bower_components/emby-webcomponents/strings/id.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Cancel", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friday", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Tipe konten:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Negara:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Bahasa:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Monday", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Saturday", - "Save": "Save", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Sunday", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Thursday", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tuesday", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Wednesday", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Cancel", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Save", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Bahasa:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Tipe konten:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Negara:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/it.json b/src/bower_components/emby-webcomponents/strings/it.json index 2e4e8823a3..ea1f5e6450 100644 --- a/src/bower_components/emby-webcomponents/strings/it.json +++ b/src/bower_components/emby-webcomponents/strings/it.json @@ -1,685 +1,689 @@ { - "Absolute": "Assoluto", - "Accept": "Accetta", - "AccessRestrictedTryAgainLater": "L'accesso è attualmente limitato. Si prega di riprovare più tardi.", - "Actor": "Attore", - "Add": "Aggiungi", - "AddToCollection": "Aggiungi ad una collezione", - "AddToPlayQueue": "Aggiungi alla coda di riproduzione", - "AddToPlaylist": "Aggiungi alla playlist", - "AddedOnValue": "Aggiunto {0}", - "Advanced": "Avanzate", - "AirDate": "Data messa in Onda", - "Aired": "In onda", - "Albums": "Album", - "All": "Tutto", - "AllChannels": "Tutti i canali", - "AllComplexFormats": "Tutti i formati complessi (ASS, SSA, VOBSUB, PGS, SUB / IDX, ecc.)", - "AllEpisodes": "Tutti gli episodi", - "AllLanguages": "Tutte le lingue", - "AllowSeasonalThemes": "Consenti temi automatici stagionali", - "AllowSeasonalThemesHelp": "Se abilitato, i temi stagionali sovrascriveranno occasionalmente l'impostazione del tema.", - "AlwaysPlaySubtitles": "Visualizza sempre i sottotitoli", - "AlwaysPlaySubtitlesHelp": "I sottotitoli corrispondenti alla lingua preferita saranno caricati a prescindere dalla lingua dell'audio.", - "AnamorphicVideoNotSupported": "Il video anamorfico non è supportato", - "AndroidUnlockRestoreHelp": "Per ripristinare il tuo acquisto precedente, per favore assicurati di essere loggato sul dispositivo con lo stesso account Google (or Amazon) dell'acquisto originale. Assicurati che l'App Store sia abilitato e non limitato da controlli parentali ed assicurati di avere una connessione ad Internet. Dovrai effettuare questa procedura una sola volta per ripristinare il tuo acquisto precendente.", - "AnyLanguage": "Qualsiasi lingua", - "Anytime": "In qualsiasi momento", - "AroundTime": "Circa {0}", - "Art": "Art", - "Artists": "Artisti", - "AsManyAsPossible": "Tutto il possibile", - "Ascending": "Crescente", - "AspectRatio": "Rapporto d'aspetto", - "AttemptingWakeServer": "Tentando di svegliare il server. Per piacere aspetta...", - "AttributeNew": "Nuovo", - "AudioBitDepthNotSupported": "La profondità bit audio non è supportata", - "AudioBitrateNotSupported": "Bitrate audio non supportato", - "AudioChannelsNotSupported": "Canali audio non supportati", - "AudioCodecNotSupported": "Il codec audio non è supportato", - "AudioProfileNotSupported": "Profilo audio non supportato", - "AudioSampleRateNotSupported": "Il tasso di campionamento audio non è supportato", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (basato sull'impostazione della lingua)", - "AutomaticallyConvertNewContent": "Converti automaticamente i nuovi contenuti", - "AutomaticallyConvertNewContentHelp": "I nuovi contenuti aggiunti in questa cartella verranno automaticamente convertiti.", - "AutomaticallySyncNewContent": "Scarica automaticamente i nuovi contenuti", - "AutomaticallySyncNewContentHelp": "I nuovi contenuti aggiunti verranno scaricati automaticamente al dispositivo.", - "Backdrop": "Sfondo", - "Backdrops": "Sfondi", - "Banner": "Banner", - "BestFit": "Adatta", - "BirthLocation": "Luogo di nascita", - "Books": "Libri", - "Box": "Box", - "BoxRear": "Box (retro)", - "Browse": "Esplora", - "BurnSubtitlesHelp": "Determina se il server deve applicare i sottotitoli quando si converte i video in base al formato dei sottotitoli. Evitando di applicare i sottotitoli migliorerà le prestazioni del server. Selezionare Auto per applicare formati basati sull'immagine (ad esempio VOBSUB, PGS, SUB / IDX, ecc.) così come alcuni sottotitoli ASS / SSA", - "ButtonCancel": "Annulla", - "ButtonGotIt": "Ho capito", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Riproduci un minuto", - "ButtonRestart": "Riavvia", - "ButtonRestorePreviousPurchase": "Ripristina Acquisto", - "ButtonTryAgain": "Riprova ancora", - "ButtonUnlockPrice": "Sblocca {0}", - "ButtonUnlockWithPurchase": "Sblocca con l'Acquisto", - "CancelDownload": "Annulla scaricamento", - "CancelRecording": "Annulla la registrazione", - "CancelSeries": "Annulla Serie TV", - "Categories": "Categorie", - "ChannelNameOnly": "Solo il canale {0}", - "ChannelNumber": "Numero canale", - "CinemaModeConfigurationHelp": "La modalità Cinema porta l'esperienza del teatro direttamente nel tuo salotto con la possibilità di vedere trailer e intro personalizzati", - "CinemaModeFeatureDescription": "Modalità Cinema ti fa provare la vera esperienza del cinema con trailer ed intro personalizzate prima del contenuto principale.", - "CloudSyncFeatureDescription": "Sincronizza i tuoi media nel cloud per un facile backup, archiviazione e conversione.", - "Collections": "Collezioni", - "ColorPrimaries": "Colori primari", - "ColorSpace": "Spazio Colore", - "ColorTransfer": "Trasferimento Colore", - "CommunityRating": "Voto del pubblico", - "Composer": "Compositore", - "ConfigureDateAdded": "Scegli come determinare la data di aggiunta dal Pannello di Controllo del Server Jellyfin, nelle impostazioni della Libreria.", - "ConfirmDeleteImage": "Elimina immagine?", - "ConfirmDeleteItem": "L'eliminazione di questo elemento lo cancellerà sia dal disco che dalla libreria multimediale. Sei sicuro di voler continuare?", - "ConfirmDeleteItems": "L'eliminazione di questi elementi li cancellerà sia dal disco che dalla tua libreria multimediale. Sei sicuro di voler continuare?", - "ConfirmDeletion": "Conferma Eliminazione", - "ConfirmEndPlayerSession": "Vuoi chiudere Jellyfin su {0}?", - "ConfirmRemoveDownload": "Rimuovi scaricamento?", - "Connect": "Connetti", - "ContainerBitrateExceedsLimit": "Il bitrate del file multimediale supera il limite.", - "ContainerNotSupported": "Contenitore file non supportato", - "Continue": "Continua", - "ContinueInSecondsValue": "Continua tra {0} secondi.", - "ContinueWatching": "Continua a guardare", - "Continuing": "In corso", - "Convert": "Converti", - "ConvertItemLimitHelp": "Opzionale. Impostare un limite al numero di elementi che verranno convertiti.", - "ConvertUnwatchedVideosOnly": "Converti solo video non visti", - "ConvertUnwatchedVideosOnlyHelp": "Verranno convertiti solo video non visti", - "ConvertingDots": "Converting...", - "Countries": "Nazioni", - "CriticRating": "Voto della critica", - "DateAdded": "Aggiunto il", - "DatePlayed": "Visto il", - "Days": "Giorni", - "Default": "Predefinito", - "DefaultErrorMessage": "Si è verificato un errore durante l'elaborazione della richiesta. Si prega di riprovare più tardi.", - "DefaultSubtitlesHelp": "I sottotitoli vengono letti in base agli attributi predefiniti e forzati dai metadati integrati. Le preferenze di lingua sono prese in considerazione quando sono disponibili più opzioni.", - "Delete": "Elimina", - "DeleteMedia": "Elimina media", - "Depressed": "Depresso", - "Descending": "Decrescente", - "Desktop": "PC Fisso", - "DirectPlayError": "Errore riproduzione diretta", - "DirectPlaying": "Riproduzione Diretta", - "DirectStreamHelp1": "Il file multimediale è compatibile con il dispositivo per quanto riguarda la risoluzione e il tipo di supporto (H. 264, AC3, etc.), ma è in un contenitore file incompatibile (.mkv, .avi, .wmv, etc.). Il video sarà ri-confezionato al volo prima di streammarlo sul dispositivo.", - "DirectStreamHelp2": "Lo Streaming in Diretta di un file utilizza poco il processore senza alcuna perdita di qualità video", - "DirectStreaming": "Streaming Diretto", - "Director": "Regista", - "DirectorValue": "Regista: {0}", - "DirectorsValue": "Registi: {0}", - "Disc": "Disco", - "Disconnect": "Disconnetti", - "Dislike": "Non mi piace", - "Display": "Schermo", - "DisplayInMyMedia": "Visualizza nella schermata di home", - "DisplayInOtherHomeScreenSections": "Mostra le sezioni della schermata home come gli ultimi media e continua a guardare", - "DisplayMissingEpisodesWithinSeasons": "Visualizza gli episodi mancanti nelle stagioni", - "DisplayMissingEpisodesWithinSeasonsHelp": "Questo deve anche essere abilitato per le librerie TV nella configurazione del Server Jellyfin.", - "DisplayModeHelp": "Scegli il tipo di schermo su cui stai utilizzando Jellyfin.", - "DoNotRecord": "Non registrare", - "Down": "Giù", - "Download": "Scarica", - "DownloadItemLimitHelp": "Facoltativo. Imposta un limite al numero di elementi che verranno scaricati.", - "Downloaded": "Scaricato", - "Downloading": "In scaricamento", - "DownloadingDots": "In scaricamento...", - "Downloads": "Scaricamenti", - "DownloadsValue": "{0} downloads", - "DropShadow": "Ombreggiato", - "DvrFeatureDescription": "Pianifica le registrazioni di Live TV, registrazioni di serie e altro ancora con Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR richiede un abbonamento ad Jellyfin Premiere.", - "Edit": "Modifica", - "EditImages": "Modifica immagini", - "EditMetadata": "Modifica metadati", - "EditSubtitles": "Modifica i sottotitoli", - "EnableBackdrops": "Abilita gli sfondi", - "EnableBackdropsHelp": "Se abilitato gli sfondi verranno riprodotti mentre visualizzi la tua libreria.", - "EnableCinemaMode": "Attiva modalità cinema", - "EnableColorCodedBackgrounds": "Abilita sfondi a colori", - "EnableDisplayMirroring": "Abilita visualizzazione remota", - "EnableExternalVideoPlayers": "Abilita lettori video esterni", - "EnableExternalVideoPlayersHelp": "Quando viene avviata la riproduzione video, verrà visualizzato un menu del riproduttore esterno .", - "EnableNextVideoInfoOverlay": "Abilita le informazioni del prossimo video durante la riproduzione", - "EnableNextVideoInfoOverlayHelp": "Alla fine di un video, visualizza informazioni sul video successivo che compare nella playlist corrente.", - "EnableThemeSongs": "Abilita tema canzoni", - "EnableThemeSongsHelp": "Se abiltato le canzoni a tema saranno riprodotte mentre visualizzi la tua libreria.", - "EnableThemeVideos": "Abilita tema video", - "EnableThemeVideosHelp": "Se abiltato, i video a tema saranno riprodotti mentre visualizzi la tua libreria", - "Ended": "Finito", - "EndsAtValue": "Finirà alle {0}", - "Episodes": "Episodi", - "Error": "Errore", - "ErrorAddingGuestAccount1": "C'è stato un errore nell'aggiunta dell'account Jellyfin Connect. Il tuo ospite ha creato un account Jellyfin? Si può registrare su {0}.", - "ErrorAddingGuestAccount2": "Se stai avendo ancora dei problemi,per piacere invia una email a {0}, e includi il tuo indirizzo email così come il loro.", - "ErrorAddingJellyfinConnectAccount1": "C'è stato un errore nell'aggiunta dell'account Jellyfin Connect. Hai creato un account Jellyfin? Registrati su {0}.", - "ErrorAddingJellyfinConnectAccount2": "Se stai ancora avendo un problema, per piacere invia una email a {0} dall'indirizzo email utilizzato con l'account Jellyfin.", - "ErrorConnectServerUnreachable": "Si è verificato un errore durante l'esecuzione dell'operazione richiesta. Il tuo server non è in grado di contattare il nostro Server Jellyfin Connect al {0}. Assicurarsi che il server disponga di una connessione Internet attiva e che le comunicazioni siano consentite da qualsiasi firewall o software di protezione installato.", - "ErrorDeletingItem": "Si è verificato un errore durante l'eliminazione dell'elemento da Jellyfin Server. Verifica che Jellyfin Server abbia accesso in scrittura sulla cartella multimediale e riprova.", - "ErrorReachingJellyfinConnect": "Si è verificato un errore durante la connessione al server Jellyfin Connect. Per favore verifica la tua connessione ad Internet e riprova.", - "ErrorRemovingJellyfinConnectAccount": "C'è stato un errore nella rimozione dell'account Jellyfin Connect. Per favore assicurati di avere una connessione a internet attiva e riprova.", - "ExtraLarge": "Molto Grande", - "Extras": "Extra", - "Favorite": "Preferito", - "Favorites": "Preferiti", - "FeatureRequiresJellyfinPremiere": "Questa funzionalità richiede un abbonamento ad Jellyfin Premiere.", - "Features": "Caratteristiche", - "File": "File", - "Fill": "Riempi", - "Filters": "Filtri", - "Folders": "Cartelle", - "FormatValue": "Formato: {0}", - "FreeAppsFeatureDescription": "Godi dell'accesso gratuito alle App Jellyfin dai tuoi dispositivi.", - "Friday": "Venerdì", - "GenreValue": "Genere: {0}", - "Genres": "Generi", - "GenresValue": "Generi: {0}", - "GroupBySeries": "Raggruppa per serie", - "GroupVersions": "Raggruppa versioni", - "GuestStar": "Personaggio famoso", - "GuestUserNotFound": "Utente non trovato. Assicurati che il nome sia corretto e riprovare o provare ad inserire l'indirizzo email.", - "Guide": "Guida", - "HDPrograms": "Programmi HD", - "HeaderActiveRecordings": "Registrazioni Attive", - "HeaderAddToCollection": "Aggiungi ad una Collezione", - "HeaderAddToPlaylist": "Aggiungi alla Playlist", - "HeaderAddUpdateImage": "Aggiungi/aggiorna Immagine", - "HeaderAlbumArtists": "Artisti Album", - "HeaderAlreadyPaid": "Hai già pagato?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audiolibri", - "HeaderAudioSettings": "Impostazioni audio", - "HeaderBecomeProjectSupporter": "Ottieni Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefici di Jellyfin Premiere", - "HeaderCancelRecording": "Annulla la Registrazione", - "HeaderCancelSeries": "Annulla Serie TV", - "HeaderCinemaMode": "Modalità Cinema", - "HeaderCloudSync": "Sinc. nel Cloud", - "HeaderConfirmRecordingCancellation": "Conferma Eliminazione Registrazione", - "HeaderContinueListening": "Continua ad ascoltare", - "HeaderContinueWatching": "Continua a guardare", - "HeaderConvertYourRecordings": "Converti le tue Registrazioni", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Elimina Elemento", - "HeaderDeleteItems": "Elimina Elementi", - "HeaderDisplaySettings": "Impostazioni Video", - "HeaderDownloadSettings": "Impostazioni Download", - "HeaderEditImages": "Modifica Immagini", - "HeaderEnabledFields": "Campi Abilitati", - "HeaderEnabledFieldsHelp": "Deseleziona un campo per bloccarlo ed impedire che venga modificato.", - "HeaderExternalIds": "Id esterni:", - "HeaderFavoriteAlbums": "Album Preferiti", - "HeaderFavoriteArtists": "Artisti Preferiti", - "HeaderFavoriteCollections": "Collezioni Preferite", - "HeaderFavoriteEpisodes": "Episodi Preferiti", - "HeaderFavoriteGames": "Giochi Preferiti", - "HeaderFavoriteMovies": "Film Preferiti", - "HeaderFavoritePlaylists": "Playlist Preferite", - "HeaderFavoriteShows": "Serie TV Preferite", - "HeaderFavoriteSongs": "Canzoni Preferite", - "HeaderFavoriteVideos": "Video Preferiti", - "HeaderFreeApps": "App Gratuite Jellyfin", - "HeaderHomeScreen": "Pagina iniziale", - "HeaderIdentifyItemHelp": "Inserisci uno o più criteri di ricerca. Rimuovi criteri per ottenere più risultati.", - "HeaderInvitationSent": "Invito inviato", - "HeaderJellyfinAccountAdded": "Account Jellyfin Aggiunto", - "HeaderJellyfinAccountRemoved": "Account Jellyfin Rimosso", - "HeaderKeepRecording": "Mantieni la registrazione", - "HeaderKeepSeries": "Mantieni Serie TV", - "HeaderLatestChannelItems": "Ultimi elementi aggiunti", - "HeaderLatestChannelMedia": "Ultimi elementi aggiunti", - "HeaderLatestFrom": "Ultime da {0}", - "HeaderLatestMedia": "Ultimi Media", - "HeaderLatestRecordings": "Ultime registrazioni", - "HeaderLearnMore": "Saperne di più", - "HeaderLibraryFolders": "Cartelle Libreria", - "HeaderLibraryOrder": "Ordine Libreria", - "HeaderMetadataSettings": "Impostazioni Metadati", - "HeaderMusicQuality": "Qualità Musica", - "HeaderMyDevice": "Il Mio Dispositivo", - "HeaderMyDownloads": "I Miei Download", - "HeaderMyMedia": "I miei media", - "HeaderMyMediaSmall": "I miei media (piccolo)", - "HeaderNewRecording": "Nuova Registrazione", - "HeaderNextEpisodePlayingInValue": "Il prossimo Episodio verrà riprodotto in {0}", - "HeaderNextUp": "Prossimo", - "HeaderNextVideoPlayingInValue": "Il prossimo Video verrà riprodotto in {0}", - "HeaderOfflineDownloads": "Media Offline", - "HeaderOfflineDownloadsDescription": "Scarica facilmente i media sui tuoi dispositivi per vederli offline.", - "HeaderOnNow": "In onda ora", - "HeaderPhotoAlbums": "Album foto", - "HeaderPlayMyMedia": "Riproduci i miei Media", - "HeaderPlayOn": "Riproduci Su", - "HeaderPlaybackError": "Errore di riproduzione", - "HeaderRecordingOptions": "Opzioni di Registrazione", - "HeaderRemoteControl": "Telecomando", - "HeaderRestartingJellyfinServer": "Riavviando Jellyfin Server", - "HeaderSaySomethingLike": "Pronuncia qualcosa come...", - "HeaderSecondsValue": "{0} Secondi", - "HeaderSelectDate": "Scegli una data", - "HeaderSeriesOptions": "Impostazioni Serie TV", - "HeaderSeriesStatus": "Stato Serie TV", - "HeaderSpecialEpisodeInfo": "Informazioni Episodio Speciale", - "HeaderStartNow": "Inizia Ora", - "HeaderStopRecording": "Ferma registrazione", - "HeaderSubtitleAppearance": "Visualizzazione Sottotitoli", - "HeaderSubtitleSettings": "Impostazioni Sottotitoli", - "HeaderSyncRequiresSub": "Per usare la funzione Download è richiesto un abbonamento Jellyfin Premiere attivo.", - "HeaderTermsOfPurchase": "Termini di pagamento", - "HeaderTryPlayback": "Prova la riproduzione", - "HeaderUnlockFeature": "Sblocca Funzionalità", - "HeaderUploadImage": "Carica immagine", - "HeaderVideoQuality": "Qualità Video", - "HeaderVideoType": "Tipo di Video", - "HeaderWaitingForWifi": "In attesa di Wifi", - "HeaderWakeServer": "Sveglia il server", - "HeaderYouSaid": "Hai detto...", - "Help": "Aiuto", - "Hide": "Nascondi", - "HideWatchedContentFromLatestMedia": "Nascondi i contenuti già visti dagli Ultimi Media", - "Home": "Home", - "Horizontal": "Orizzontale", - "HowDidYouPay": "Come hai pagato?", - "IHaveJellyfinPremiere": "Sono abbonato ad Jellyfin Premiere", - "IPurchasedThisApp": "Ho acquistato questa app", - "Identify": "Identifica", - "Images": "Immagini", - "ImdbRating": "Voto IMDB", - "InstallingPackage": "Installazione di {0}", - "InstantMix": "Mix istantaneo", - "InterlacedVideoNotSupported": "Il video interlacciato non è supportato", - "ItemCount": "{0} elementi", - "Items": "Elementi", - "KeepDownload": "Continua a scaricare", - "KeepOnDevice": "Mantieni sul dispositivo", - "Kids": "Bambini", - "Label3DFormat": "Formato 3D:", - "LabelAirDays": "In onda da (gg):", - "LabelAirTime": "In onda da:", - "LabelAirsAfterSeason": "In onda dopo la stagione:", - "LabelAirsBeforeEpisode": "In onda prima dell'episodio:", - "LabelAirsBeforeSeason": "In onda prima della stagione:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Artisti album:", - "LabelArtists": "Artisti:", - "LabelArtistsHelp": "Separa valori multipli usando ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Lingua audio preferita:", - "LabelBirthDate": "Data di nascita:", - "LabelBirthYear": "Anno di nascita:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Applica sottotitoli:", - "LabelChannels": "Canali:", - "LabelCollection": "Collezione:", - "LabelCommunityRating": "Voto del pubblico:", - "LabelContentType": "Tipo di contenuto:", - "LabelConvertTo": "Converti a:", - "LabelCountry": "Nazione:", - "LabelCriticRating": "Voto della critica:", - "LabelCustomRating": "Voto personalizzato:", - "LabelDashboardTheme": "Tema dashboard del server:", - "LabelDateAdded": "Aggiunto il:", - "LabelDateTimeLocale": "Data locale:", - "LabelDeathDate": "Anno di morte:", - "LabelDefaultScreen": "Schermo predefinito:", - "LabelDiscNumber": "Numero disco:", - "LabelDisplayLanguage": "Lingua di visualizzazione:", - "LabelDisplayLanguageHelp": "La traduzione di Jellyfin è un progetto attivo.", - "LabelDisplayMode": "Modalità di visualizzazione:", - "LabelDisplayOrder": "Ordine di visualizzazione:", - "LabelDropImageHere": "Rilasciare l'immagine qui, oppure clicca per sfogliare.", - "LabelDropShadow": "Ombreggiatura:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "Indirizzo e-mail:", - "LabelEndDate": "Data di fine:", - "LabelEpisodeNumber": "Numero espisodio:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Qualità della rete domestica:", - "LabelHomeScreenSectionValue": "Pagina iniziale Sezione {0}:", - "LabelImageType": "Tipo immagine:", - "LabelInternetQuality": "Qualità Internet:", - "LabelItemLimit": "Limite elementi:", - "LabelKeep:": "Conserva:", - "LabelKeepUpTo": "Conservane fino a:", - "LabelLanguage": "Lingua:", - "LabelLockItemToPreventChanges": "Blocca questo elemento per impedire modifiche future", - "LabelMaxChromecastBitrate": "Qualità streaming su Chromecast:", - "LabelMetadataDownloadLanguage": "Lingua preferita per lo scaricamento:", - "LabelName": "Nome:", - "LabelNumber": "Numero:", - "LabelOriginalAspectRatio": "Aspetto originale:", - "LabelOriginalTitle": "Titolo originale:", - "LabelOverview": "Trama:", - "LabelParentNumber": "Numero precursore:", - "LabelParentalRating": "Classificazione per genitori:", - "LabelPath": "Percorso:", - "LabelPersonRole": "Ruolo:", - "LabelPersonRoleHelp": "Esempio: Autista di chiosco dei gelati", - "LabelPlaceOfBirth": "Luogo di nascita:", - "LabelPlayDefaultAudioTrack": "Riprodurre la traccia audio di default indipendentemente dalla lingua", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Lingua dei sottotitoli preferita:", - "LabelProfile": "Profilo:", - "LabelQuality": "Qualità:", - "LabelReasonForTranscoding": "Motivo per la transcodifica:", - "LabelRecord": "Registra:", - "LabelRefreshMode": "Modalità di aggiornamento:", - "LabelReleaseDate": "Data di uscita:", - "LabelRuntimeMinutes": "Durata (minuti):", - "LabelScreensaver": "Salvaschermo:", - "LabelSeasonNumber": "Numero stagione:", - "LabelSelectFolderGroups": "Raggruppa i contenuti delle seguenti cartelle in viste come Film, Musica e Serie TV", - "LabelSelectFolderGroupsHelp": "Le cartelle non selezionate verranno mostrate come se stesse nelle proprie viste", - "LabelShortOverview": "Trama breve:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Durata salta indietro:", - "LabelSkipForwardLength": "Durata salta avanti:", - "LabelSortBy": "Ordina per:", - "LabelSortOrder": "Ordinato per:", - "LabelSortTitle": "Titolo per ordinamento:", - "LabelSoundEffects": "Effetti sonori:", - "LabelSource": "Origine:", - "LabelStartWhenPossible": "Avvia appena possibile:", - "LabelStatus": "Stato:", - "LabelStopWhenPossible": "Ferma appena possibile:", - "LabelSubtitlePlaybackMode": "Modalità Sottotitolo:", - "LabelSubtitles": "Sottotitoli:", - "LabelSyncJobName": "Nome Attività di Sinc.:", - "LabelSyncNoTargetsHelp": "Al momento non hai applicazioni che supportino il download offline.", - "LabelSyncTo": "Sincronizza su:", - "LabelTVHomeScreen": "Schermata iniziale della modalità TV:", - "LabelTagline": "Slogan:", - "LabelTextBackgroundColor": "Colore di sfondo del testo:", - "LabelTextColor": "Colore testo:", - "LabelTextSize": "Dimensione testo:", - "LabelTheme": "Tema:", - "LabelTitle": "Titolo:", - "LabelTrackNumber": "Numero traccia:", - "LabelType": "Tipo:", - "LabelVersion": "Versione:", - "LabelVideo": "Video:", - "LabelWebsite": "Sito Web:", - "LabelWindowBackgroundColor": "Colore di sfondo del testo:", - "LabelYear": "Anno:", - "Large": "Grande", - "LatestFromLibrary": "Ultimi {0}", - "LearnHowYouCanContribute": "Scopri come puoi contribuire.", - "LearnMore": "saperne di più", - "Like": "Mi piace", - "LinksValue": "Collegamenti: {0}", - "List": "Lista", - "Live": "In diretta", - "LiveBroadcasts": "Tramissioni in diretta", - "LiveTV": "Diretta TV", - "LiveTvFeatureDescription": "Stream Live TV a qualsiasi applicazione Jellyfin, con un dispositivo di sintonizzatore TV compatibile installato sul server Jellyfin.", - "LiveTvRequiresUnlock": "La TV in diretta richiede un abbonamento Jellyfin Premiere attivo.", - "Logo": "Logo", - "ManageRecording": "Gestisci registrazione", - "MarkPlayed": "Segna visto", - "MarkUnplayed": "Segna non visto", - "MarkWatched": "Segna come visto", - "MediaIsBeingConverted": "Il file multimediale viene convertito in un formato che è compatibile con il dispositivo che sta riproducendo il file multimediale.", - "Medium": "Medio", - "Menu": "Menù", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Un abbonamento a Jellyfin Premiere è necessario per creare registrazioni personalizzate delle serie tv", - "MessageAreYouSureDeleteSubtitles": "Sei sicuro di voler eliminare questo file di sottotitoli?", - "MessageConfirmRecordingCancellation": "Cancellare la registrazione?", - "MessageDownloadQueued": "Scaricamento programmato.", - "MessageFileReadError": "Si è verificato un errore durante la lettura del file. Si prega di riprovare.", - "MessageIfYouBlockedVoice": "Se hai negato l'accesso vocale all'app dovrai riconfigurarlo prima di riprovare di nuovo.", - "MessageInvitationSentToNewUser": "Un'email è stata inviata a {0} invitandolo a registrarsi a Jellyfin", - "MessageInvitationSentToUser": "Una e-mail è stata inviata a {0}, invitandoli ad accettare l'invito di condivisione.", - "MessageItemSaved": "Elemento salvato.", - "MessageItemsAdded": "Elementi aggiunti.", - "MessageJellyfinAccontRemoved": "L'account Jellyfin è stato rimosso da questo utente", - "MessageJellyfinAccountAdded": "L'account Jellyfin è stato aggiunto a questo utente", - "MessageLeaveEmptyToInherit": "Lascia vuoto per ereditare le impostazioni dall'elemento principale, o il valore predefinito globale.", - "MessageNoDownloadsFound": "Nessun download offline trovato. Scarica i tuoi media per renderli disponibili offline usando l'opzione Download sull'applicazione.", - "MessageNoServersAvailableToConnect": "Nessun server disponibile per la connessione. Se siete stati invitati a condividere un server, assicuratevi di accettare l'invito qui sotto o cliccando sul collegamento nella e-mail.", - "MessageNoSyncJobsFound": "Nessun download trovato. Puoi creare un'attività di download usando il bottone di Download presente nell'applicazione.", - "MessagePendingJellyfinAccountAdded": "L'account Jellyfin è stato aggiunto a questo utente. Un'email sarà inviata al proprietario dell'account. L'invito dovrà essere confermato selezionando il link contenuto nell'email", - "MessagePlayAccessRestricted": "Le riproduzione di questi contenuti è bloccata. Per favore contatta il tuo amministratore Jellyfin Server per maggiori informazioni.", - "MessageToValidateSupporter": "Se hai un abbonamento Jellyfin Premiere, assicurati di averlo configurato nel Pannello di Controllo del Server, a cui puoi accedere cliccando su Jellyfin Premiere dal menu principale.", - "MessageUnlockAppWithPurchaseOrSupporter": "Sblocca questa funzionalità con un piccolo acquisto singolo, o con un abbonamento Jellyfin Premiere.", - "MessageUnlockAppWithSupporter": "Sblocca questa funzionalità con un abbonamento Jellyfin Premiere", - "MessageWeDidntRecognizeCommand": "Ci dispiace, non riconosciamo il comando.", - "MinutesAfter": "minuti dopo", - "MinutesBefore": "minuti prima", - "Mobile": "Mobile / Tablet", - "Monday": "Lunedì", - "More": "Dettagli", - "MoveLeft": "Sposta a sinistra", - "MoveRight": "Sposta a destra", - "Movies": "Film", - "MySubtitles": "I miei Sottotitoli", - "Name": "Nome", - "NewCollection": "Nuova Collezione", - "NewCollectionHelp": "Le collezioni ti permettono di creare raccolte personalizzate di film ed altri contenuti della libreria.", - "NewCollectionNameExample": "Esempio: Collezione Star wars", - "NewEpisodes": "Nuovi episodi", - "NewEpisodesOnly": "Solo i nuovi episodi", - "News": "Notizie", - "Next": "Prossimo", - "No": "No", - "NoItemsFound": "Nessun elemento trovato.", - "NoSubtitleSearchResultsFound": "Nessun risultato.", - "NoSubtitles": "Nessun Sottotitolo", - "NoSubtitlesHelp": "I sottotitoli non verranno caricati per impostazione predefinita.Possono essere ancora caricati manualmente durante la riproduzione.", - "None": "Nessuno", - "Normal": "Normale", - "Off": "Spento", - "OneChannel": "Un canale", - "OnlyForcedSubtitles": "Solo i sottotitoli forzati", - "OnlyForcedSubtitlesHelp": "Solo i sottotitoli contrassegnati come forzati saranno caricati.", - "OnlyImageFormats": "Solo formati immagine (VOBSUB, PGS, SUB / IDX, ecc.)", - "Open": "Apri", - "OptionNew": "Nuovo...", - "Original": "Originale", - "OriginalAirDateValue": "Prima messa in onda (originale): {0}", - "Overview": "Trama", - "PackageInstallCancelled": "Installazione di {0} annullata.", - "PackageInstallCompleted": "Installazione di {0} completa.", - "PackageInstallFailed": "Installazione di {0} fallita.", - "ParentalRating": "Classificazione per genitori", - "People": "Attori", - "PerfectMatch": "Corrispondenza perfetta", - "Photos": "Foto", - "PlaceFavoriteChannelsAtBeginning": "Mostra prima i canali preferiti", - "Play": "Riproduci", - "PlayAllFromHere": "Riproduci tutto da qui in poi", - "PlayCount": "Riproduzioni", - "PlayFromBeginning": "Riproduci dall'inizio", - "PlayNext": "Riproduci prossimo", - "PlayNextEpisodeAutomatically": "Riproduci automaticamente l'episodio successivo", - "PlaybackErrorNoCompatibleStream": "Nessuna trasmissione compatibile è al momento disponibile. Per favore riprova in seguito o contatta il tuo Amministratore di sistema per chiarimenti", - "PlaybackErrorNotAllowed": "Al momento non sei autorizzato a riprodurre questo contenuto. Per favore contatta l'amministratore del sistema per ulteriori dettagli", - "PlaybackErrorPlaceHolder": "Per favore inserisci i dischi nell'ordine per riprodurre questo video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Visto", - "Playlists": "Playlist", - "PleaseEnterNameOrId": "Per favore inserisci un nome o un id esterno.", - "PleaseRestartServerName": "Per favore riavvia Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Seleziona un dispositivo per eseguire il download.", - "PleaseSelectTwoItems": "Seleziona almeno due elementi.", - "Premiere": "Prima visione", - "Premieres": "Prime Visioni", - "Previous": "Precedente", - "Primary": "Locandina", - "PrivacyPolicy": "Informativa sulla privacy", - "Producer": "Produttore", - "ProductionLocations": "Sedi di produzione", - "Programs": "Programmi", - "PromoConvertRecordingsToStreamingFormat": "Converti automaticamente le registrazioni in un formato adatto allo streaming con Jellyfin Premiere. Le registrazioni saranno convertite in tempo reale ad MP4 o MKV, in base alle impostazioni del server.", - "Quality": "Qualità", - "QueueAllFromHere": "In coda tutto da qui in poi", - "Raised": "Sospeso", - "RecentlyWatched": "Visti di recente", - "Record": "Registra", - "RecordSeries": "Registra serie TV", - "RecordingCancelled": "Registrazione annullata.", - "RecordingScheduled": "Registrazione pianificata.", - "Recordings": "Registrazioni", - "RefFramesNotSupported": "Il numero di frame di riferimento video non è supportato", - "Refresh": "Aggiorna", - "RefreshDialogHelp": "I Metadati sono aggiornati in base alle impostazioni ed ai servizi Internet abilitati nel Pannello di Controllo del Server Jellyfin.", - "RefreshMetadata": "Aggiorna metadati", - "RefreshQueued": "Aggiornamento programmato.", - "Reject": "Rifiuta", - "ReleaseDate": "Data di uscita", - "RemoveDownload": "Rimuovi scaricamento", - "RemoveFromCollection": "Rimuovi dalla collezione", - "RemoveFromPlaylist": "Rimuovi dalla playlist", - "RemovingFromDevice": "Rimuovendo dal dispositivo", - "Repeat": "Ripeti", - "RepeatAll": "Ripeti tutti", - "RepeatEpisodes": "Ripeti episodi", - "RepeatMode": "Modalità Ripeti", - "RepeatOne": "Ripeti uno", - "ReplaceAllMetadata": "Sostituisci tutti i metadati", - "ReplaceExistingImages": "Sovrascrivi immagini esistenti", - "RestartPleaseWaitMessage": "Per piacere aspetta mentre Jellyfin Server si arresta e riavvia. Questo può richiedere un minuto o due.", - "ResumeAt": "Riprendi da {0}", - "Retry": "Riprova", - "RunAtStartup": "Esegui all'avvio", - "Runtime": "Durata", - "Saturday": "Sabato", - "Save": "Salva", - "ScanForNewAndUpdatedFiles": "Scansiona per file nuovi e aggiornati", - "Schedule": "Programmazione", - "Screenshot": "Immagine", - "Screenshots": "Screenshot", - "Search": "Cerca", - "SearchForCollectionInternetMetadata": "Cerca su internet le immagini ed i metadati", - "SearchForMissingMetadata": "Cerca metadati mancanti", - "SearchForSubtitles": "Cerca Sottotitoli", - "SearchResults": "Risultati della Ricerca", - "SecondaryAudioNotSupported": "Il cambiamento della traccia audio non è supportato", - "SeriesCancelled": "Serie TV annullate.", - "SeriesDisplayOrderHelp": "Ordina gli episodi per data messa in onda, ordine dvd o numerazione assoluta.", - "SeriesRecordingScheduled": "Registrazione serie TV pianificata.", - "SeriesSettings": "Impostazioni Serie TV", - "SeriesYearToPresent": "{0} - Oggi", - "ServerNameIsRestarting": "Jellyfin Server - {0} si sta riavviando.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} si sta arrestando.", - "ServerUpdateNeeded": "Questo server Jellyfin deve essere aggiornato. Per scaricare l'ultima versione vai su {0}", - "Settings": "Impostazioni", - "SettingsSaved": "Settaggi salvati.", - "Share": "Condividi", - "ShowIndicatorsFor": "Mostra indicatori per:", - "ShowTitle": "Mostra titolo", - "ShowYear": "Mostra anno", - "Shows": "Programmi", - "Shuffle": "Casuale", - "SkipEpisodesAlreadyInMyLibrary": "Non registrare gli espisodi che sono già in libreria", - "SkipEpisodesAlreadyInMyLibraryHelp": "Gli episodi verranno confrontati usando la stagione ed il numero dell'episodio, quando disponibili.", - "Small": "Piccolo", - "SmallCaps": "Maiuscoletto", - "Smaller": "Smaller", - "Smart": "Intelligente", - "SmartSubtitlesHelp": "I sottotitoli che coincidono con la lingua nelle preferenze verranno caricati quando l'audio sarà in una lingua straniera.", - "Songs": "Canzoni", - "Sort": "Ordina", - "SortByValue": "Ordina per {0}", - "SortChannelsBy": "Ordina canali per:", - "SortName": "Nome ordinamento", - "Sports": "Sport", - "StatsForNerds": "Statistiche per nerds", - "StopRecording": "Ferma registrazione", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Queste impostazioni si applicano anche a qualsiasi riproduzione di Chromecast avviata da questo dispositivo.", - "SubtitleAppearanceSettingsDisclaimer": "Queste impostazioni non si applicano a sottotitoli grafici (PGS, DVD, ecc.), o sottotitoli che hanno i propri stili incorporati (ASS / SSA).", - "SubtitleCodecNotSupported": "Il formato del sottotitolo non è supportato", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Sottotitoli", - "Suggestions": "Suggerimenti", - "Sunday": "Domenica", - "Sync": "Sincronizza", - "SyncJobItemStatusCancelled": "Annullato", - "SyncJobItemStatusConverting": "Convertendo", - "SyncJobItemStatusFailed": "Fallito", - "SyncJobItemStatusQueued": "In coda", - "SyncJobItemStatusReadyToTransfer": "Pronto per il trasferimento", - "SyncJobItemStatusRemovedFromDevice": "Rimosso dal dispositivo", - "SyncJobItemStatusSynced": "Scaricato", - "SyncJobItemStatusSyncedMarkForRemoval": "Rimuovendo dal dispositivo", - "SyncJobItemStatusTransferring": "Trasferendo", - "SyncUnwatchedVideosOnly": "Scarica solo i video non visti", - "SyncUnwatchedVideosOnlyHelp": "Solo i video non visti verranno scaricati, e verranno rimossi dal dispositivo non appena visti.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tag", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Termini di utilizzo", - "ThankYouForTryingEnjoyOneMinute": "Siamo lieti di offrirti un minuto di riproduzione. Grazie per aver provato Jellyfin.", - "ThemeSongs": "Temi canzoni", - "ThemeVideos": "Temi video", - "TheseSettingsAffectSubtitlesOnThisDevice": "Queste impostazioni influenzano i sottotitoli di questo dispositivo", - "Thumb": "Miniatura", - "Thursday": "Giovedì", - "TrackCount": "{0} tracce", - "Trailer": "Trailer", - "Trailers": "Trailer", - "Transcoding": "Trascodifica", - "TryMultiSelect": "Prova la selezione multipla", - "TryMultiSelectMessage": "Per modificare più elementi, clicca e tieni premuto su un poster e seleziona gli elementi che vuoi gestire. Prova!", - "Tuesday": "Martedì", - "Uniform": "Uniforme", - "UnlockGuide": "Sblocca Guida", - "Unplayed": "Non visto", - "Unrated": "Non votato", - "UntilIDelete": "Finchè li elimino", - "UntilSpaceNeeded": "Finchè c'è spazio", - "Up": "Su", - "Upload": "Carica", - "ValueAlbumCount": "{0} album", - "ValueDiscNumber": "Disco {0}", - "ValueEpisodeCount": "{0} episodi", - "ValueGameCount": "{0} giochi", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} film", - "ValueMusicVideoCount": "{0} video musicali", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episodio", - "ValueOneGame": "1 gioco", - "ValueOneItem": "1 elemento", - "ValueOneMovie": "1 film", - "ValueOneMusicVideo": "1 video musicale", - "ValueOneSeries": "1 serie TV", - "ValueOneSong": "1 brano", - "ValueSeconds": "{0} secondi", - "ValueSeriesCount": "{0} serie TV", - "ValueSongCount": "{0} brani", - "ValueSpecialEpisodeName": "Speciale - {0}", - "Vertical": "Verticale", - "VideoBitDepthNotSupported": "La profondità di bit video non è supportata", - "VideoCodecNotSupported": "Il codec video non è supportato", - "VideoFramerateNotSupported": "Framerate video non supportato", - "VideoLevelNotSupported": "Livello video non supportato", - "VideoProfileNotSupported": "Profilo video non supportato", - "VideoRange": "Range del Video", - "VideoResolutionNotSupported": "Risoluzione video non supportata", - "ViewAlbum": "Visualizza album", - "ViewArtist": "Visualizza artista", - "VoiceInput": "Comandi Vocali", - "WakeServer": "Sveglia il server", - "WakeServerError": "I pacchetti Wake On LAN sono stati inviati al computer server, ma non siamo in grado di connettersi al server Jellyfin. Potrebbe essere necessario un po 'più di tempo per riattivare la macchina, oppure il server Jellyfin potrebbe non essere attivo sulla macchina.", - "WakeServerSuccess": "Successo!", - "Watched": "Visto", - "Wednesday": "Mercoledì", - "WifiRequiredToDownload": "Una connessione Wifi è richiesta per continuare il download", - "Writer": "Scrittore", - "Yes": "Si" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "Sblocca questa funzionalit\u00e0 con un piccolo acquisto singolo, o con un abbonamento Emby Premiere.", + "MessageUnlockAppWithSupporter": "Sblocca questa funzionalit\u00e0 con un abbonamento Emby Premiere", + "MessageToValidateSupporter": "Se hai un abbonamento Emby Premiere, assicurati di averlo configurato nel Pannello di Controllo del Server, a cui puoi accedere cliccando su Emby Premiere dal menu principale.", + "ValueSpecialEpisodeName": "Speciale - {0}", + "Share": "Condividi", + "Add": "Aggiungi", + "ServerUpdateNeeded": "Questo server Emby deve essere aggiornato. Per scaricare l'ultima versione vai su {0}", + "LiveTvRequiresUnlock": "La TV in diretta richiede un abbonamento Emby Premiere attivo.", + "AttributeNew": "Nuovo", + "Premiere": "Prima visione", + "Live": "In diretta", + "Repeat": "Ripeti", + "TrackCount": "{0} tracce", + "ItemCount": "{0} elementi", + "OriginalAirDateValue": "Prima messa in onda (originale): {0}", + "EndsAtValue": "Finir\u00e0 alle {0}", + "HeaderSelectDate": "Scegli una data", + "Watched": "Visto", + "AirDate": "Data messa in Onda", + "Played": "Visto", + "ButtonOk": "Ok", + "ButtonCancel": "Annulla", + "AccessRestrictedTryAgainLater": "L'accesso \u00e8 attualmente limitato. Si prega di riprovare pi\u00f9 tardi.", + "ButtonGotIt": "Ho capito", + "ButtonRestart": "Riavvia", + "RecordingCancelled": "Registrazione annullata.", + "SeriesCancelled": "Serie TV annullate.", + "RecordingScheduled": "Registrazione pianificata.", + "SeriesRecordingScheduled": "Registrazione serie TV pianificata.", + "HeaderNewRecording": "Nuova Registrazione", + "WakeServer": "Sveglia il server", + "HeaderWakeServer": "Sveglia il server", + "AttemptingWakeServer": "Tentando di svegliare il server. Per piacere aspetta...", + "WakeServerSuccess": "Successo!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "I pacchetti Wake On LAN sono stati inviati al computer server, ma non siamo in grado di connettersi al server Emby. Potrebbe essere necessario un po 'pi\u00f9 di tempo per riattivare la macchina, oppure il server Emby potrebbe non essere attivo sulla macchina.", + "Sunday": "Domenica", + "Monday": "Luned\u00ec", + "Tuesday": "Marted\u00ec", + "Wednesday": "Mercoled\u00ec", + "Thursday": "Gioved\u00ec", + "Friday": "Venerd\u00ec", + "Saturday": "Sabato", + "Days": "Giorni", + "SortByValue": "Ordina per {0}", + "LabelSortBy": "Ordina per:", + "LabelSortOrder": "Ordinato per:", + "HeaderPhotoAlbums": "Album foto", + "Photos": "Foto", + "HeaderAppearsOn": "Appears On", + "List": "Lista", + "RecordSeries": "Registra serie TV", + "HeaderCinemaMode": "Modalit\u00e0 Cinema", + "HeaderCloudSync": "Sinc. nel Cloud", + "Downloads": "Scaricamenti", + "HeaderMyDownloads": "I Miei Download", + "HeaderOfflineDownloads": "Media Offline", + "HeaderOfflineDownloadsDescription": "Scarica facilmente i media sui tuoi dispositivi per vederli offline.", + "CloudSyncFeatureDescription": "Sincronizza i tuoi media nel cloud per un facile backup, archiviazione e conversione.", + "LiveTvFeatureDescription": "Stream Live TV a qualsiasi applicazione Emby, con un dispositivo di sintonizzatore TV compatibile installato sul server Emby.", + "DvrFeatureDescription": "Pianifica le registrazioni di Live TV, registrazioni di serie e altro ancora con Emby DVR.", + "CinemaModeFeatureDescription": "Modalit\u00e0 Cinema ti fa provare la vera esperienza del cinema con trailer ed intro personalizzate prima del contenuto principale.", + "HeaderFreeApps": "App Gratuite Emby", + "FreeAppsFeatureDescription": "Godi dell'accesso gratuito alle App Emby dai tuoi dispositivi.", + "HeaderBecomeProjectSupporter": "Ottieni Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Un abbonamento a Emby Premiere \u00e8 necessario per creare registrazioni personalizzate delle serie tv", + "LabelEmailAddress": "Indirizzo e-mail:", + "PromoConvertRecordingsToStreamingFormat": "Converti automaticamente le registrazioni in un formato adatto allo streaming con Emby Premiere. Le registrazioni saranno convertite in tempo reale ad MP4 o MKV, in base alle impostazioni del server.", + "FeatureRequiresEmbyPremiere": "Questa funzionalit\u00e0 richiede un abbonamento ad Emby Premiere.", + "HeaderConvertYourRecordings": "Converti le tue Registrazioni", + "Record": "Registra", + "Save": "Salva", + "Edit": "Modifica", + "Download": "Scarica", + "Downloaded": "Scaricato", + "Downloading": "In scaricamento", + "Advanced": "Avanzate", + "Delete": "Elimina", + "HeaderDeleteItem": "Elimina Elemento", + "ConfirmDeleteItem": "L'eliminazione di questo elemento lo canceller\u00e0 sia dal disco che dalla libreria multimediale. Sei sicuro di voler continuare?", + "Refresh": "Aggiorna", + "RefreshQueued": "Aggiornamento programmato.", + "AddToCollection": "Aggiungi ad una collezione", + "HeaderAddToCollection": "Aggiungi ad una Collezione", + "NewCollection": "Nuova Collezione", + "LabelCollection": "Collezione:", + "Help": "Aiuto", + "LabelDisplayMode": "Modalit\u00e0 di visualizzazione:", + "Desktop": "PC Fisso", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Scegli il tipo di schermo su cui stai utilizzando Emby.", + "LabelDisplayLanguage": "Lingua di visualizzazione:", + "LabelDisplayLanguageHelp": "La traduzione di Emby \u00e8 un progetto attivo.", + "LearnHowYouCanContribute": "Scopri come puoi contribuire.", + "NewCollectionHelp": "Le collezioni ti permettono di creare raccolte personalizzate di film ed altri contenuti della libreria.", + "SearchForCollectionInternetMetadata": "Cerca su internet le immagini ed i metadati", + "DisplayMissingEpisodesWithinSeasons": "Visualizza gli episodi mancanti nelle stagioni", + "DisplayMissingEpisodesWithinSeasonsHelp": "Questo deve anche essere abilitato per le librerie TV nella configurazione del Server Emby.", + "EnableThemeSongs": "Abilita tema canzoni", + "EnableBackdrops": "Abilita gli sfondi", + "EnableThemeSongsHelp": "Se abiltato le canzoni a tema saranno riprodotte mentre visualizzi la tua libreria.", + "EnableBackdropsHelp": "Se abilitato gli sfondi verranno riprodotti mentre visualizzi la tua libreria.", + "EnableThemeVideos": "Abilita tema video", + "EnableThemeVideosHelp": "Se abiltato, i video a tema saranno riprodotti mentre visualizzi la tua libreria", + "RunAtStartup": "Esegui all'avvio", + "LabelScreensaver": "Salvaschermo:", + "LabelSoundEffects": "Effetti sonori:", + "LabelSkin": "Skin:", + "LabelName": "Nome:", + "NewCollectionNameExample": "Esempio: Collezione Star wars", + "MessageItemsAdded": "Elementi aggiunti.", + "OptionNew": "Nuovo...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Aggiungi alla playlist", + "HeaderAddToPlaylist": "Aggiungi alla Playlist", + "Subtitles": "Sottotitoli", + "LabelTheme": "Tema:", + "LabelDashboardTheme": "Tema dashboard del server:", + "SearchForSubtitles": "Cerca Sottotitoli", + "LabelLanguage": "Lingua:", + "Search": "Cerca", + "NoSubtitleSearchResultsFound": "Nessun risultato.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Sei sicuro di voler eliminare questo file di sottotitoli?", + "ConfirmDeletion": "Conferma Eliminazione", + "MySubtitles": "I miei Sottotitoli", + "MessageDownloadQueued": "Scaricamento programmato.", + "EditSubtitles": "Modifica i sottotitoli", + "UnlockGuide": "Sblocca Guida", + "RefreshMetadata": "Aggiorna metadati", + "ReplaceExistingImages": "Sovrascrivi immagini esistenti", + "ReplaceAllMetadata": "Sostituisci tutti i metadati", + "SearchForMissingMetadata": "Cerca metadati mancanti", + "LabelRefreshMode": "Modalit\u00e0 di aggiornamento:", + "NoItemsFound": "Nessun elemento trovato.", + "HeaderSaySomethingLike": "Pronuncia qualcosa come...", + "ButtonTryAgain": "Riprova ancora", + "HeaderYouSaid": "Hai detto...", + "MessageWeDidntRecognizeCommand": "Ci dispiace, non riconosciamo il comando.", + "MessageIfYouBlockedVoice": "Se hai negato l'accesso vocale all'app dovrai riconfigurarlo prima di riprovare di nuovo.", + "ValueDiscNumber": "Disco {0}", + "Unrated": "Non votato", + "Favorite": "Preferito", + "Like": "Mi piace", + "Dislike": "Non mi piace", + "RefreshDialogHelp": "I Metadati sono aggiornati in base alle impostazioni ed ai servizi Internet abilitati nel Pannello di Controllo del Server Emby.", + "Open": "Apri", + "Play": "Riproduci", + "AddToPlayQueue": "Aggiungi alla coda di riproduzione", + "Shuffle": "Casuale", + "Identify": "Identifica", + "EditImages": "Modifica immagini", + "EditMetadata": "Modifica metadati", + "Convert": "Converti", + "Sync": "Sincronizza", + "InstantMix": "Mix istantaneo", + "ViewAlbum": "Visualizza album", + "ViewArtist": "Visualizza artista", + "QueueAllFromHere": "In coda tutto da qui in poi", + "PlayAllFromHere": "Riproduci tutto da qui in poi", + "PlayFromBeginning": "Riproduci dall'inizio", + "ResumeAt": "Riprendi da {0}", + "RemoveFromPlaylist": "Rimuovi dalla playlist", + "RemoveFromCollection": "Rimuovi dalla collezione", + "Sort": "Ordina", + "Trailer": "Trailer", + "MarkPlayed": "Segna visto", + "MarkUnplayed": "Segna non visto", + "GroupVersions": "Raggruppa versioni", + "PleaseSelectTwoItems": "Seleziona almeno due elementi.", + "TryMultiSelect": "Prova la selezione multipla", + "TryMultiSelectMessage": "Per modificare pi\u00f9 elementi, clicca e tieni premuto su un poster e seleziona gli elementi che vuoi gestire. Prova!", + "HeaderConfirmRecordingCancellation": "Conferma Eliminazione Registrazione", + "MessageConfirmRecordingCancellation": "Cancellare la registrazione?", + "Error": "Errore", + "VoiceInput": "Comandi Vocali", + "LabelContentType": "Tipo di contenuto:", + "LabelPath": "Percorso:", + "Playlists": "Playlist", + "LabelTitle": "Titolo:", + "LabelOriginalTitle": "Titolo originale:", + "LabelSortTitle": "Titolo per ordinamento:", + "LabelDateAdded": "Aggiunto il:", + "DateAdded": "Aggiunto il", + "DatePlayed": "Visto il", + "ConfigureDateAdded": "Scegli come determinare la data di aggiunta dal Pannello di Controllo del Server Emby, nelle impostazioni della Libreria.", + "LabelStatus": "Stato:", + "LabelArtists": "Artisti:", + "LabelArtistsHelp": "Separa valori multipli usando ;", + "HeaderAlbumArtists": "Artisti Album", + "LabelAlbumArtists": "Artisti album:", + "LabelAlbum": "Album:", + "Artists": "Artisti", + "ImdbRating": "Voto IMDB", + "CommunityRating": "Voto del pubblico", + "LabelCommunityRating": "Voto del pubblico:", + "LabelCriticRating": "Voto della critica:", + "CriticRating": "Voto della critica", + "LabelWebsite": "Sito Web:", + "LabelTagline": "Slogan:", + "LabelOverview": "Trama:", + "LabelShortOverview": "Trama breve:", + "LabelReleaseDate": "Data di uscita:", + "LabelYear": "Anno:", + "LabelPlaceOfBirth": "Luogo di nascita:", + "Aired": "In onda", + "LabelAirDays": "In onda da (gg):", + "LabelAirTime": "In onda da:", + "LabelRuntimeMinutes": "Durata (minuti):", + "LabelParentalRating": "Classificazione per genitori:", + "LabelCustomRating": "Voto personalizzato:", + "LabelOriginalAspectRatio": "Aspetto originale:", + "Label3DFormat": "Formato 3D:", + "FormatValue": "Formato: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Corrispondenza perfetta", + "EnableExternalVideoPlayers": "Abilita lettori video esterni", + "EnableExternalVideoPlayersHelp": "Quando viene avviata la riproduzione video, verr\u00e0 visualizzato un menu del riproduttore esterno .", + "HeaderSpecialEpisodeInfo": "Informazioni Episodio Speciale", + "LabelAirsBeforeSeason": "In onda prima della stagione:", + "LabelAirsAfterSeason": "In onda dopo la stagione:", + "LabelAirsBeforeEpisode": "In onda prima dell'episodio:", + "HeaderExternalIds": "Id esterni:", + "HeaderDisplaySettings": "Impostazioni Video", + "LabelDisplayOrder": "Ordine di visualizzazione:", + "Display": "Schermo", + "Countries": "Nazioni", + "Genres": "Generi", + "Studios": "Studios", + "Tags": "Tag", + "HeaderMetadataSettings": "Impostazioni Metadati", + "People": "Attori", + "LabelMetadataDownloadLanguage": "Lingua preferita per lo scaricamento:", + "LabelLockItemToPreventChanges": "Blocca questo elemento per impedire modifiche future", + "MessageLeaveEmptyToInherit": "Lascia vuoto per ereditare le impostazioni dall'elemento principale, o il valore predefinito globale.", + "LabelCountry": "Nazione:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Anno di nascita:", + "LabelBirthDate": "Data di nascita:", + "LabelDeathDate": "Anno di morte:", + "LabelEndDate": "Data di fine:", + "LabelSeasonNumber": "Numero stagione:", + "LabelEpisodeNumber": "Numero espisodio:", + "LabelTrackNumber": "Numero traccia:", + "LabelNumber": "Numero:", + "LabelDiscNumber": "Numero disco:", + "LabelParentNumber": "Numero precursore:", + "SortName": "Nome ordinamento", + "ReleaseDate": "Data di uscita", + "Continuing": "In corso", + "Ended": "Finito", + "HeaderEnabledFields": "Campi Abilitati", + "HeaderEnabledFieldsHelp": "Deseleziona un campo per bloccarlo ed impedire che venga modificato.", + "Backdrops": "Sfondi", + "Images": "Immagini", + "Runtime": "Durata", + "ProductionLocations": "Sedi di produzione", + "BirthLocation": "Luogo di nascita", + "ParentalRating": "Classificazione per genitori", + "PlayCount": "Riproduzioni", + "Name": "Nome", + "Overview": "Trama", + "LabelType": "Tipo:", + "LabelPersonRole": "Ruolo:", + "LabelPersonRoleHelp": "Esempio: Autista di chiosco dei gelati", + "Actor": "Attore", + "Composer": "Compositore", + "Director": "Regista", + "GuestStar": "Personaggio famoso", + "Producer": "Produttore", + "Writer": "Scrittore", + "MessageNoSyncJobsFound": "Nessun download trovato. Puoi creare un'attivit\u00e0 di download usando il bottone di Download presente nell'applicazione.", + "MessageNoDownloadsFound": "Nessun download offline trovato. Scarica i tuoi media per renderli disponibili offline usando l'opzione Download sull'applicazione.", + "InstallingPackage": "Installazione di {0}", + "PackageInstallCompleted": "Installazione di {0} completa.", + "PackageInstallFailed": "Installazione di {0} fallita.", + "PackageInstallCancelled": "Installazione di {0} annullata.", + "SeriesYearToPresent": "{0} - Oggi", + "ValueOneItem": "1 elemento", + "ValueOneSong": "1 brano", + "ValueSongCount": "{0} brani", + "ValueOneMovie": "1 film", + "ValueMovieCount": "{0} film", + "ValueOneSeries": "1 serie TV", + "ValueSeriesCount": "{0} serie TV", + "ValueOneEpisode": "1 episodio", + "ValueEpisodeCount": "{0} episodi", + "ValueOneGame": "1 gioco", + "ValueGameCount": "{0} giochi", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} album", + "ValueOneMusicVideo": "1 video musicale", + "ValueMusicVideoCount": "{0} video musicali", + "ValueMinutes": "{0} min", + "Albums": "Album", + "Songs": "Canzoni", + "Books": "Libri", + "HeaderAudioBooks": "Audiolibri", + "HeaderIdentifyItemHelp": "Inserisci uno o pi\u00f9 criteri di ricerca. Rimuovi criteri per ottenere pi\u00f9 risultati.", + "PleaseEnterNameOrId": "Per favore inserisci un nome o un id esterno.", + "MessageItemSaved": "Elemento salvato.", + "SearchResults": "Risultati della Ricerca", + "ServerNameIsRestarting": "Emby Server - {0} si sta riavviando.", + "ServerNameIsShuttingDown": "Emby Server - {0} si sta arrestando.", + "HeaderDeleteItems": "Elimina Elementi", + "ConfirmDeleteItems": "L'eliminazione di questi elementi li canceller\u00e0 sia dal disco che dalla tua libreria multimediale. Sei sicuro di voler continuare?", + "PleaseRestartServerName": "Per favore riavvia Emby Server - {0}.", + "LabelSyncJobName": "Nome Attivit\u00e0 di Sinc.:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Qualit\u00e0:", + "LabelSyncNoTargetsHelp": "Al momento non hai applicazioni che supportino il download offline.", + "DownloadingDots": "In scaricamento...", + "HeaderSyncRequiresSub": "Per usare la funzione Download \u00e8 richiesto un abbonamento Emby Premiere attivo.", + "LearnMore": "saperne di pi\u00f9", + "LabelProfile": "Profilo:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Converti solo video non visti", + "SyncUnwatchedVideosOnly": "Scarica solo i video non visti", + "ConvertUnwatchedVideosOnlyHelp": "Verranno convertiti solo video non visti", + "SyncUnwatchedVideosOnlyHelp": "Solo i video non visti verranno scaricati, e verranno rimossi dal dispositivo non appena visti.", + "AutomaticallySyncNewContent": "Scarica automaticamente i nuovi contenuti", + "AutomaticallySyncNewContentHelp": "I nuovi contenuti aggiunti verranno scaricati automaticamente al dispositivo.", + "AutomaticallyConvertNewContent": "Converti automaticamente i nuovi contenuti", + "AutomaticallyConvertNewContentHelp": "I nuovi contenuti aggiunti in questa cartella verranno automaticamente convertiti.", + "LabelItemLimit": "Limite elementi:", + "ConvertItemLimitHelp": "Opzionale. Impostare un limite al numero di elementi che verranno convertiti.", + "DownloadItemLimitHelp": "Facoltativo. Imposta un limite al numero di elementi che verranno scaricati.", + "PleaseSelectDeviceToSyncTo": "Seleziona un dispositivo per eseguire il download.", + "Screenshots": "Screenshot", + "MoveRight": "Sposta a destra", + "MoveLeft": "Sposta a sinistra", + "ConfirmDeleteImage": "Elimina immagine?", + "HeaderEditImages": "Modifica Immagini", + "Settings": "Impostazioni", + "ShowIndicatorsFor": "Mostra indicatori per:", + "NewEpisodes": "Nuovi episodi", + "Episodes": "Episodi", + "HDPrograms": "Programmi HD", + "Programs": "Programmi", + "LiveBroadcasts": "Tramissioni in diretta", + "Premieres": "Prime Visioni", + "RepeatEpisodes": "Ripeti episodi", + "DvrSubscriptionRequired": "Emby DVR richiede un abbonamento ad Emby Premiere.", + "HeaderCancelRecording": "Annulla la Registrazione", + "CancelRecording": "Annulla la registrazione", + "HeaderKeepRecording": "Mantieni la registrazione", + "HeaderCancelSeries": "Annulla Serie TV", + "HeaderKeepSeries": "Mantieni Serie TV", + "HeaderLearnMore": "Saperne di pi\u00f9", + "DeleteMedia": "Elimina media", + "SeriesSettings": "Impostazioni Serie TV", + "HeaderRecordingOptions": "Opzioni di Registrazione", + "CancelSeries": "Annulla Serie TV", + "DoNotRecord": "Non registrare", + "HeaderSeriesOptions": "Impostazioni Serie TV", + "LabelChannels": "Canali:", + "ChannelNameOnly": "Solo il canale {0}", + "Anytime": "In qualsiasi momento", + "AnyLanguage": "Qualsiasi lingua", + "AroundTime": "Circa {0}", + "All": "Tutto", + "AllChannels": "Tutti i canali", + "LabelRecord": "Registra:", + "NewEpisodesOnly": "Solo i nuovi episodi", + "AllEpisodes": "Tutti gli episodi", + "LabelStartWhenPossible": "Avvia appena possibile:", + "LabelStopWhenPossible": "Ferma appena possibile:", + "MinutesBefore": "minuti prima", + "MinutesAfter": "minuti dopo", + "SkipEpisodesAlreadyInMyLibrary": "Non registrare gli espisodi che sono gi\u00e0 in libreria", + "SkipEpisodesAlreadyInMyLibraryHelp": "Gli episodi verranno confrontati usando la stagione ed il numero dell'episodio, quando disponibili.", + "LabelKeepUpTo": "Conservane fino a:", + "AsManyAsPossible": "Tutto il possibile", + "DefaultErrorMessage": "Si \u00e8 verificato un errore durante l'elaborazione della richiesta. Si prega di riprovare pi\u00f9 tardi.", + "LabelKeep:": "Conserva:", + "UntilIDelete": "Finch\u00e8 li elimino", + "UntilSpaceNeeded": "Finch\u00e8 c'\u00e8 spazio", + "Categories": "Categorie", + "Sports": "Sport", + "News": "Notizie", + "Movies": "Film", + "Kids": "Bambini", + "EnableColorCodedBackgrounds": "Abilita sfondi a colori", + "SortChannelsBy": "Ordina canali per:", + "RecentlyWatched": "Visti di recente", + "ChannelNumber": "Numero canale", + "HeaderBenefitsEmbyPremiere": "Benefici di Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "Siamo lieti di offrirti un minuto di riproduzione. Grazie per aver provato Emby.", + "HeaderTryPlayback": "Prova la riproduzione", + "HowDidYouPay": "Come hai pagato?", + "IHaveEmbyPremiere": "Sono abbonato ad Emby Premiere", + "IPurchasedThisApp": "Ho acquistato questa app", + "ButtonRestorePreviousPurchase": "Ripristina Acquisto", + "ButtonUnlockWithPurchase": "Sblocca con l'Acquisto", + "ButtonUnlockPrice": "Sblocca {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere Mensile {0}", + "HeaderAlreadyPaid": "Hai gi\u00e0 pagato?", + "ButtonPlayOneMinute": "Riproduci un minuto", + "PlaceFavoriteChannelsAtBeginning": "Mostra prima i canali preferiti", + "HeaderUnlockFeature": "Sblocca Funzionalit\u00e0", + "MessageDidYouKnowCinemaMode": "Sapevi che con Emby Premiere puoi migliorare la tua esperienza d'uso con funzionalit\u00e0 come la Modalit\u00e0 Cinema?", + "MessageDidYouKnowCinemaMode2": "Modalit\u00e0 Cinema ti fa provare la vera esperienza del cinema con trailer ed intro personalizzate prima del contenuto principale.", + "HeaderPlayMyMedia": "Riproduci i miei Media", + "HeaderDiscoverEmbyPremiere": "Scopri Emby Premiere", + "Items": "Elementi", + "OneChannel": "Un canale", + "ConfirmRemoveDownload": "Rimuovi scaricamento?", + "RemoveDownload": "Rimuovi scaricamento", + "KeepDownload": "Continua a scaricare", + "AddedOnValue": "Aggiunto {0}", + "RemovingFromDevice": "Rimuovendo dal dispositivo", + "KeepOnDevice": "Mantieni sul dispositivo", + "CancelDownload": "Annulla scaricamento", + "SyncJobItemStatusReadyToTransfer": "Pronto per il trasferimento", + "SyncJobItemStatusSyncedMarkForRemoval": "Rimuovendo dal dispositivo", + "SyncJobItemStatusQueued": "In coda", + "SyncJobItemStatusConverting": "Convertendo", + "SyncJobItemStatusTransferring": "Trasferendo", + "SyncJobItemStatusSynced": "Scaricato", + "SyncJobItemStatusFailed": "Fallito", + "SyncJobItemStatusRemovedFromDevice": "Rimosso dal dispositivo", + "SyncJobItemStatusCancelled": "Annullato", + "Retry": "Riprova", + "HeaderMyDevice": "Il Mio Dispositivo", + "Continue": "Continua", + "ContinueInSecondsValue": "Continua tra {0} secondi.", + "HeaderRemoteControl": "Telecomando", + "Disconnect": "Disconnetti", + "EnableDisplayMirroring": "Abilita visualizzazione remota", + "HeaderPlayOn": "Riproduci Su", + "Quality": "Qualit\u00e0", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "Per ripristinare il tuo acquisto precedente, per favore assicurati di essere loggato sul dispositivo con lo stesso account Google (or Amazon) dell'acquisto originale. Assicurati che l'App Store sia abilitato e non limitato da controlli parentali ed assicurati di avere una connessione ad Internet. Dovrai effettuare questa procedura una sola volta per ripristinare il tuo acquisto precendente.", + "AspectRatio": "Rapporto d'aspetto", + "Original": "Originale", + "Fill": "Riempi", + "BestFit": "Adatta", + "MessageNoServersAvailableToConnect": "Nessun server disponibile per la connessione. Se siete stati invitati a condividere un server, assicuratevi di accettare l'invito qui sotto o cliccando sul collegamento nella e-mail.", + "MessagePlayAccessRestricted": "Le riproduzione di questi contenuti \u00e8 bloccata. Per favore contatta il tuo amministratore Emby Server per maggiori informazioni.", + "Accept": "Accetta", + "Reject": "Rifiuta", + "Connect": "Connetti", + "HeaderMyMedia": "I miei media", + "HeaderMyMediaSmall": "I miei media (piccolo)", + "LatestFromLibrary": "Ultimi {0}", + "ContinueWatching": "Continua a guardare", + "HeaderLatestChannelMedia": "Ultimi elementi aggiunti", + "HeaderContinueWatching": "Continua a guardare", + "HeaderContinueListening": "Continua ad ascoltare", + "HeaderActiveRecordings": "Registrazioni Attive", + "HeaderLatestRecordings": "Ultime registrazioni", + "LabelSyncTo": "Sincronizza su:", + "LabelConvertTo": "Converti a:", + "Next": "Prossimo", + "LabelSource": "Origine:", + "LabelVersion": "Versione:", + "AllLanguages": "Tutte le lingue", + "Previous": "Precedente", + "HeaderNextUp": "Prossimo", + "HeaderLatestFrom": "Ultime da {0}", + "LabelHomeScreenSectionValue": "Pagina iniziale Sezione {0}:", + "SettingsSaved": "Settaggi salvati.", + "None": "Nessuno", + "More": "Dettagli", + "Up": "Su", + "Down": "Gi\u00f9", + "Home": "Home", + "Favorites": "Preferiti", + "HeaderHomeScreen": "Pagina iniziale", + "HeaderLatestChannelItems": "Ultimi elementi aggiunti", + "HeaderLibraryOrder": "Ordine Libreria", + "HideWatchedContentFromLatestMedia": "Nascondi i contenuti gi\u00e0 visti dagli Ultimi Media", + "HeaderOnNow": "In onda ora", + "HeaderPlaybackError": "Errore di riproduzione", + "PlaybackErrorNotAllowed": "Al momento non sei autorizzato a riprodurre questo contenuto. Per favore contatta l'amministratore del sistema per ulteriori dettagli", + "PlaybackErrorNoCompatibleStream": "Nessuna trasmissione compatibile \u00e8 al momento disponibile. Per favore riprova in seguito o contatta il tuo Amministratore di sistema per chiarimenti", + "PlaybackErrorPlaceHolder": "Per favore inserisci i dischi nell'ordine per riprodurre questo video.", + "Guide": "Guida", + "Suggestions": "Suggerimenti", + "HeaderFavoriteCollections": "Collezioni Preferite", + "HeaderFavoritePlaylists": "Playlist Preferite", + "Collections": "Collezioni", + "LabelSelectFolderGroups": "Raggruppa i contenuti delle seguenti cartelle in viste come Film, Musica e Serie TV", + "LabelSelectFolderGroupsHelp": "Le cartelle non selezionate verranno mostrate come se stesse nelle proprie viste", + "Folders": "Cartelle", + "DisplayInOtherHomeScreenSections": "Mostra le sezioni della schermata home come gli ultimi media e continua a guardare", + "DisplayInMyMedia": "Visualizza nella schermata di home", + "Shows": "Programmi", + "HeaderLibraryFolders": "Cartelle Libreria", + "HeaderTermsOfPurchase": "Termini di pagamento", + "PrivacyPolicy": "Informativa sulla privacy", + "TermsOfUse": "Termini di utilizzo", + "RepeatMode": "Modalit\u00e0 Ripeti", + "RepeatOne": "Ripeti uno", + "RepeatAll": "Ripeti tutti", + "LabelDefaultScreen": "Schermo predefinito:", + "ConfirmEndPlayerSession": "Vuoi chiudere Emby su {0}?", + "Yes": "Si", + "No": "No", + "LiveTV": "Diretta TV", + "Schedule": "Programmazione", + "Recordings": "Registrazioni", + "MarkWatched": "Segna come visto", + "ScanForNewAndUpdatedFiles": "Scansiona per file nuovi e aggiornati", + "DirectStreamHelp1": "Il file multimediale \u00e8 compatibile con il dispositivo per quanto riguarda la risoluzione e il tipo di supporto (H. 264, AC3, etc.), ma \u00e8 in un contenitore file incompatibile (.mkv, .avi, .wmv, etc.). Il video sar\u00e0 ri-confezionato al volo prima di streammarlo sul dispositivo.", + "DirectStreamHelp2": "Lo Streaming in Diretta di un file utilizza poco il processore senza alcuna perdita di qualit\u00e0 video", + "MediaIsBeingConverted": "Il file multimediale viene convertito in un formato che \u00e8 compatibile con il dispositivo che sta riproducendo il file multimediale.", + "StatsForNerds": "Statistiche per nerds", + "LabelReasonForTranscoding": "Motivo per la transcodifica:", + "DirectPlaying": "Riproduzione Diretta", + "DirectStreaming": "Streaming Diretto", + "Transcoding": "Trascodifica", + "ContainerBitrateExceedsLimit": "Il bitrate del file multimediale supera il limite.", + "VideoCodecNotSupported": "Il codec video non \u00e8 supportato", + "AudioCodecNotSupported": "Il codec audio non \u00e8 supportato", + "SubtitleCodecNotSupported": "Il formato del sottotitolo non \u00e8 supportato", + "DirectPlayError": "Errore riproduzione diretta", + "ContainerNotSupported": "Contenitore file non supportato", + "VideoLevelNotSupported": "Livello video non supportato", + "AudioBitrateNotSupported": "Bitrate audio non supportato", + "AudioChannelsNotSupported": "Canali audio non supportati", + "VideoResolutionNotSupported": "Risoluzione video non supportata", + "AudioProfileNotSupported": "Profilo audio non supportato", + "AudioSampleRateNotSupported": "Il tasso di campionamento audio non \u00e8 supportato", + "AnamorphicVideoNotSupported": "Il video anamorfico non \u00e8 supportato", + "InterlacedVideoNotSupported": "Il video interlacciato non \u00e8 supportato", + "SecondaryAudioNotSupported": "Il cambiamento della traccia audio non \u00e8 supportato", + "ErrorRemovingEmbyConnectAccount": "C'\u00e8 stato un errore nella rimozione dell'account Emby Connect. Per favore assicurati di avere una connessione a internet attiva e riprova.", + "HeaderEmbyAccountRemoved": "Account Emby Rimosso", + "MessageEmbyAccontRemoved": "L'account Emby \u00e8 stato rimosso da questo utente", + "HeaderInvitationSent": "Invito inviato", + "MessageInvitationSentToUser": "Una e-mail \u00e8 stata inviata a {0}, invitandoli ad accettare l'invito di condivisione.", + "MessageInvitationSentToNewUser": "Un'email \u00e8 stata inviata a {0} invitandolo a registrarsi a Emby", + "GuestUserNotFound": "Utente non trovato. Assicurati che il nome sia corretto e riprovare o provare ad inserire l'indirizzo email.", + "ErrorReachingEmbyConnect": "Si \u00e8 verificato un errore durante la connessione al server Emby Connect. Per favore verifica la tua connessione ad Internet e riprova.", + "ErrorAddingEmbyConnectAccount1": "C'\u00e8 stato un errore nell'aggiunta dell'account Emby Connect. Hai creato un account Emby? Registrati su {0}.", + "ErrorAddingEmbyConnectAccount2": "Se stai ancora avendo un problema, per piacere invia una email a {0} dall'indirizzo email utilizzato con l'account Emby.", + "ErrorAddingGuestAccount1": "C'\u00e8 stato un errore nell'aggiunta dell'account Emby Connect. Il tuo ospite ha creato un account Emby? Si pu\u00f2 registrare su {0}.", + "ErrorAddingGuestAccount2": "Se stai avendo ancora dei problemi,per piacere invia una email a {0}, e includi il tuo indirizzo email cos\u00ec come il loro.", + "MessageEmbyAccountAdded": "L'account Emby \u00e8 stato aggiunto a questo utente", + "MessagePendingEmbyAccountAdded": "L'account Emby \u00e8 stato aggiunto a questo utente. Un'email sar\u00e0 inviata al proprietario dell'account. L'invito dovr\u00e0 essere confermato selezionando il link contenuto nell'email", + "HeaderEmbyAccountAdded": "Account Emby Aggiunto", + "LabelSubtitlePlaybackMode": "Modalit\u00e0 Sottotitolo:", + "ErrorDeletingItem": "Si \u00e8 verificato un errore durante l'eliminazione dell'elemento da Emby Server. Verifica che Emby Server abbia accesso in scrittura sulla cartella multimediale e riprova.", + "NoSubtitles": "Nessun Sottotitolo", + "Default": "Predefinito", + "Absolute": "Assoluto", + "Smart": "Intelligente", + "Small": "Piccolo", + "Smaller": "Smaller", + "Medium": "Medio", + "Large": "Grande", + "ExtraLarge": "Molto Grande", + "OnlyForcedSubtitles": "Solo i sottotitoli forzati", + "AlwaysPlaySubtitles": "Visualizza sempre i sottotitoli", + "DefaultSubtitlesHelp": "I sottotitoli vengono letti in base agli attributi predefiniti e forzati dai metadati integrati. Le preferenze di lingua sono prese in considerazione quando sono disponibili pi\u00f9 opzioni.", + "SmartSubtitlesHelp": "I sottotitoli che coincidono con la lingua nelle preferenze verranno caricati quando l'audio sar\u00e0 in una lingua straniera.", + "HeaderSubtitleSettings": "Impostazioni Sottotitoli", + "HeaderSubtitleAppearance": "Visualizzazione Sottotitoli", + "OnlyForcedSubtitlesHelp": "Solo i sottotitoli contrassegnati come forzati saranno caricati.", + "AlwaysPlaySubtitlesHelp": "I sottotitoli corrispondenti alla lingua preferita saranno caricati a prescindere dalla lingua dell'audio.", + "NoSubtitlesHelp": "I sottotitoli non verranno caricati per impostazione predefinita.Possono essere ancora caricati manualmente durante la riproduzione.", + "LabelPreferredSubtitleLanguage": "Lingua dei sottotitoli preferita:", + "LabelTextSize": "Dimensione testo:", + "TheseSettingsAffectSubtitlesOnThisDevice": "Queste impostazioni influenzano i sottotitoli di questo dispositivo", + "LabelDropShadow": "Ombreggiatura:", + "LabelTextBackgroundColor": "Colore di sfondo del testo:", + "LabelWindowBackgroundColor": "Colore di sfondo del testo:", + "LabelFont": "Font:", + "LabelTextColor": "Colore testo:", + "Raised": "Sospeso", + "Depressed": "Depresso", + "Uniform": "Uniforme", + "DropShadow": "Ombreggiato", + "SmallCaps": "Maiuscoletto", + "SubtitleAppearanceSettingsDisclaimer": "Queste impostazioni non si applicano a sottotitoli grafici (PGS, DVD, ecc.), o sottotitoli che hanno i propri stili incorporati (ASS \/ SSA).", + "LabelBurnSubtitles": "Applica sottotitoli:", + "OnlyImageFormats": "Solo formati immagine (VOBSUB, PGS, SUB \/ IDX, ecc.)", + "Normal": "Normale", + "BurnSubtitlesHelp": "Determina se il server deve applicare i sottotitoli quando si converte i video in base al formato dei sottotitoli. Evitando di applicare i sottotitoli migliorer\u00e0 le prestazioni del server. Selezionare Auto per applicare formati basati sull'immagine (ad esempio VOBSUB, PGS, SUB \/ IDX, ecc.) cos\u00ec come alcuni sottotitoli ASS \/ SSA", + "AllComplexFormats": "Tutti i formati complessi (ASS, SSA, VOBSUB, PGS, SUB \/ IDX, ecc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Queste impostazioni si applicano anche a qualsiasi riproduzione di Chromecast avviata da questo dispositivo.", + "HeaderWaitingForWifi": "In attesa di Wifi", + "WifiRequiredToDownload": "Una connessione Wifi \u00e8 richiesta per continuare il download", + "HeaderDownloadSettings": "Impostazioni Download", + "Hide": "Nascondi", + "HeaderStartNow": "Inizia Ora", + "HeaderNextVideoPlayingInValue": "Il prossimo Video verr\u00e0 riprodotto in {0}", + "HeaderNextEpisodePlayingInValue": "Il prossimo Episodio verr\u00e0 riprodotto in {0}", + "HeaderSecondsValue": "{0} Secondi", + "AudioBitDepthNotSupported": "La profondit\u00e0 bit audio non \u00e8 supportata", + "VideoProfileNotSupported": "Profilo video non supportato", + "VideoFramerateNotSupported": "Framerate video non supportato", + "VideoBitDepthNotSupported": "La profondit\u00e0 di bit video non \u00e8 supportata", + "RefFramesNotSupported": "Il numero di frame di riferimento video non \u00e8 supportato", + "ErrorConnectServerUnreachable": "Si \u00e8 verificato un errore durante l'esecuzione dell'operazione richiesta. Il tuo server non \u00e8 in grado di contattare il nostro Server Emby Connect al {0}. Assicurarsi che il server disponga di una connessione Internet attiva e che le comunicazioni siano consentite da qualsiasi firewall o software di protezione installato.", + "StopRecording": "Ferma registrazione", + "HeaderStopRecording": "Ferma registrazione", + "ManageRecording": "Gestisci registrazione", + "LabelDropImageHere": "Rilasciare l'immagine qui, oppure clicca per sfogliare.", + "MessageFileReadError": "Si \u00e8 verificato un errore durante la lettura del file. Si prega di riprovare.", + "Browse": "Esplora", + "HeaderUploadImage": "Carica immagine", + "HeaderAddUpdateImage": "Aggiungi\/aggiorna Immagine", + "LabelImageType": "Tipo immagine:", + "Upload": "Carica", + "Primary": "Locandina", + "Art": "Art", + "Backdrop": "Sfondo", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (retro)", + "Disc": "Disco", + "Logo": "Logo", + "Menu": "Men\u00f9", + "Screenshot": "Immagine", + "Thumb": "Miniatura", + "ValueSeconds": "{0} secondi", + "HeaderAudioSettings": "Impostazioni audio", + "LabelAudioLanguagePreference": "Lingua audio preferita:", + "LabelPlayDefaultAudioTrack": "Riprodurre la traccia audio di default indipendentemente dalla lingua", + "HeaderVideoQuality": "Qualit\u00e0 Video", + "CinemaModeConfigurationHelp": "La modalit\u00e0 Cinema porta l'esperienza del teatro direttamente nel tuo salotto con la possibilit\u00e0 di vedere trailer e intro personalizzati", + "EnableNextVideoInfoOverlay": "Abilita le informazioni del prossimo video durante la riproduzione", + "EnableNextVideoInfoOverlayHelp": "Alla fine di un video, visualizza informazioni sul video successivo che compare nella playlist corrente.", + "PlayNextEpisodeAutomatically": "Riproduci automaticamente l'episodio successivo", + "LabelMaxChromecastBitrate": "Qualit\u00e0 streaming su Chromecast:", + "LabelSkipBackLength": "Durata salta indietro:", + "LabelSkipForwardLength": "Durata salta avanti:", + "EnableCinemaMode": "Attiva modalit\u00e0 cinema", + "LabelInternetQuality": "Qualit\u00e0 Internet:", + "HeaderMusicQuality": "Qualit\u00e0 Musica", + "LabelHomeNetworkQuality": "Qualit\u00e0 della rete domestica:", + "HeaderLatestMedia": "Ultimi Media", + "HeaderRestartingEmbyServer": "Riavviando Emby Server", + "RestartPleaseWaitMessage": "Per piacere aspetta mentre Emby Server si arresta e riavvia. Questo pu\u00f2 richiedere un minuto o due.", + "PlayNext": "Riproduci prossimo", + "AllowSeasonalThemes": "Consenti temi automatici stagionali", + "AllowSeasonalThemesHelp": "Se abilitato, i temi stagionali sovrascriveranno occasionalmente l'impostazione del tema.", + "AutoBasedOnLanguageSetting": "Auto (basato sull'impostazione della lingua)", + "LabelDateTimeLocale": "Data locale:", + "DirectorValue": "Regista: {0}", + "DirectorsValue": "Registi: {0}", + "GenreValue": "Genere: {0}", + "GenresValue": "Generi: {0}", + "LinksValue": "Collegamenti: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Sottotitoli:", + "Off": "Spento", + "ShowTitle": "Mostra titolo", + "ShowYear": "Mostra anno", + "Filters": "Filtri", + "Unplayed": "Non visto", + "LabelTVHomeScreen": "Schermata iniziale della modalit\u00e0 TV:", + "Horizontal": "Orizzontale", + "Vertical": "Verticale", + "GroupBySeries": "Raggruppa per serie", + "HeaderVideoType": "Tipo di Video", + "HeaderSeriesStatus": "Stato Serie TV", + "Features": "Caratteristiche", + "Trailers": "Trailer", + "Extras": "Extra", + "ThemeSongs": "Temi canzoni", + "ThemeVideos": "Temi video", + "HeaderFavoriteMovies": "Film Preferiti", + "HeaderFavoriteShows": "Serie TV Preferite", + "HeaderFavoriteEpisodes": "Episodi Preferiti", + "HeaderFavoriteVideos": "Video Preferiti", + "HeaderFavoriteGames": "Giochi Preferiti", + "HeaderFavoriteArtists": "Artisti Preferiti", + "HeaderFavoriteAlbums": "Album Preferiti", + "HeaderFavoriteSongs": "Canzoni Preferite", + "Ascending": "Crescente", + "Descending": "Decrescente", + "ColorPrimaries": "Colori primari", + "ColorSpace": "Spazio Colore", + "ColorTransfer": "Trasferimento Colore", + "VideoRange": "Range del Video", + "SeriesDisplayOrderHelp": "Ordina gli episodi per data messa in onda, ordine dvd o numerazione assoluta.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/kk.json b/src/bower_components/emby-webcomponents/strings/kk.json index 2f45becfc9..226533b19b 100644 --- a/src/bower_components/emby-webcomponents/strings/kk.json +++ b/src/bower_components/emby-webcomponents/strings/kk.json @@ -1,685 +1,689 @@ { - "Absolute": "Түпнұсқалық", - "Accept": "Қабылдау", - "AccessRestrictedTryAgainLater": "Ағымда қатынау шектелген. Әрекетті кейін қайталаңыз.", - "Actor": "Актер", - "Add": "Үстеу", - "AddToCollection": "Жиынтыққа үстеу", - "AddToPlayQueue": "Ойнату кезегіне үстеу", - "AddToPlaylist": "Ойнату тізіміне үстеу", - "AddedOnValue": "Үстелгені {0}", - "Advanced": "Кеңейтілген", - "AirDate": "Эфир күні", - "Aired": "Эфирлік", - "Albums": "Альбомдар", - "All": "Бәрі", - "AllChannels": "Барлық арналар", - "AllComplexFormats": "Барлық күрделі пішімдері (ASS, SSA, VOBSUB, PGS, SUB/IDX және т.б.)", - "AllEpisodes": "Барлық бөлімдер", - "AllLanguages": "Барлық тілдер", - "AllowSeasonalThemes": "Автоматты түрдегі маусымдық тақырыптарға рұқсат ету", - "AllowSeasonalThemesHelp": "Қосылған болса, маусымдық тақырыптар анда-санда тақырып параметрлеріңіздің күшін жояды.", - "AlwaysPlaySubtitles": "Субтитрлерді әрқашан ойнату", - "AlwaysPlaySubtitlesHelp": "Тіл теңшеліміне сәйкес келген субтитрлер дыбыс тіліне қатыссыз жүктеледі.", - "AnamorphicVideoNotSupported": "Анаморфтық бейне үшін қолдау көрсетілмейді", - "AndroidUnlockRestoreHelp": "Алдыңғы сатып алуды қалпына келтіру үшін, бастапқыда сатып алу жасалған нақ сол Google (немесе Amazon) тіркелгісімен құрылғыға кіріңіз. Қолданба дүкені қосылған және кез келген ата-ана шектеусіз, және белсенді интернет байланысы бар екеніне көз жеткізіңіз. Алдыңғы сатып алу қалпына келтіру үшін мұны тек қана бір рет істеу керек.", - "AnyLanguage": "Қай-қайсы тіл", - "Anytime": "Әркезде", - "AroundTime": "{0} айналасында", - "Art": "Ою сурет", - "Artists": "Орындаушылар", - "AsManyAsPossible": "Мүмкіндігінше көп", - "Ascending": "Артуы бойынша", - "AspectRatio": "Пішімдік арақатынасы", - "AttemptingWakeServer": "Серверді ояту әрекеті жасалуда. Күте тұрыңыз...", - "AttributeNew": "Жаңа", - "AudioBitDepthNotSupported": "Дыбыстың биттік тереңдігі үшін қолдау көрсетілмейді", - "AudioBitrateNotSupported": "Дыбыс қарқыны үшін қолдау көрсетілмейді", - "AudioChannelsNotSupported": "Дыбыс арналары үшін қолдау көрсетілмейді", - "AudioCodecNotSupported": "Дыбыс кодек қолдауда емес", - "AudioProfileNotSupported": "Дыбыс профайлы үшін қолдау көрсетілмейді", - "AudioSampleRateNotSupported": "Үлгі жиілігі үшін қолдау көрсетілмейді", - "Auto": "Автоматты", - "AutoBasedOnLanguageSetting": "Автоматты түрде (тіл теңшелімі негізінде)", - "AutomaticallyConvertNewContent": "Жаңа мазмұнды автоматты түрде түрлендіру", - "AutomaticallyConvertNewContentHelp": "Осы қальаға жаңадан қосылған мазмұн автоматты түрде осы түрлендірледі.", - "AutomaticallySyncNewContent": "Жаңа мазмұнды автоматты түрде жүктеу", - "AutomaticallySyncNewContentHelp": "Осы қалтаға жаңадан қосылған мазмұн автоматты түрде осы құр-ғыға жүктеледі.", - "Backdrop": "Артқы сурет", - "Backdrops": "Артқы суреттер", - "Banner": "Баннер", - "BestFit": "Қиыстыру", - "BirthLocation": "Туған орны", - "Books": "Кітаптар", - "Box": "Қорап", - "BoxRear": "Қорап арты", - "Browse": "Шарлау", - "BurnSubtitlesHelp": "Субтитрлер пішіміне байланысты бейнені түрлендірген кезде сервер субтитрлерді жазыуын анықтайды. Субтитрлер жазуды қашқақтау сервердің өнімділігін жақсартады. Суретке негізделген пішімдерді (мысалы, VOBSUB, PGS, SUB/IDX ж.т.б.), сондай-ақ кейбір ASS/SSA субтитрлерін жазу үшін Автоматтыны таңдаңыз", - "ButtonCancel": "Болдырмау", - "ButtonGotIt": "Түсінікті", - "ButtonOk": "Жарайды", - "ButtonPlayOneMinute": "Бір минөт ойнату", - "ButtonRestart": "Қайта іске қосу", - "ButtonRestorePreviousPurchase": "Сатып алғанды қалпына келтіру", - "ButtonTryAgain": "Әрекетті қайталау", - "ButtonUnlockPrice": "{0} құлыптамау", - "ButtonUnlockWithPurchase": "Сатып алумен құрсаудан босату", - "CancelDownload": "Жүктеп алуды болдырмау", - "CancelRecording": "Жазуды болдырмау", - "CancelSeries": "Телехикаяны болдырмау", - "Categories": "Санаттар", - "ChannelNameOnly": "Тек қана {0} арнасы", - "ChannelNumber": "Арна нөмірі", - "CinemaModeConfigurationHelp": "Кинотеатр режімі трейлерлерді және теңшелген көрнеуді негізгі фильм алдында ойнату кинозал әсерін жеткізеді.", - "CinemaModeFeatureDescription": "Кинотеатр режімі трейлерлерді және теңшелген көрнеуді фильм алдында ойнату кинозал әсерін жеткізеді.", - "CloudSyncFeatureDescription": "Сақтық көшірмені, мұрағаттауды және түрлендіруді жеңілдету үшін тасығыш деректерді бұлтпен үндестіріңіз.", - "Collections": "Жиынтықтар", - "ColorPrimaries": "Түс негізгілері", - "ColorSpace": "Түс кеңістігі", - "ColorTransfer": "Түс аустыруы", - "CommunityRating": "Қауым бағалауы", - "Composer": "Композитор", - "ConfigureDateAdded": "Үстелген күні Jellyfin Server тақтасындағы Тасығышхана параметрлерінде анықталады", - "ConfirmDeleteImage": "Суретті жоямыз ба?", - "ConfirmDeleteItem": "Осы тармақты жойғанда, ол файл жүйесінен де, тасығышханаңыздан да жойылады. Шынымен жалғастыру қажет пе?", - "ConfirmDeleteItems": "Осы тармақтарды жойғанда, олар файлдық жүйесінен де және тасығышханаңыздан да екеуінде жойылад. Сіз жалғастыру қалайсыз ба? Шынымен жалғастыру қажет пе?", - "ConfirmDeletion": "Жоюды растау", - "ConfirmEndPlayerSession": "Jellyfin жұмысын аяқтауды {0} құрылғыда қалайсыз ба?", - "ConfirmRemoveDownload": "Жүктеуді аластаймыз ба?", - "Connect": "Қосылу", - "ContainerBitrateExceedsLimit": "Тасығышдеректер қарқыны шегінен артты.", - "ContainerNotSupported": "Контейнер үшін қолдау көрсетілмейді", - "Continue": "Жалғастыру", - "ContinueInSecondsValue": "Жалғасы {0} с кейін", - "ContinueWatching": "Қарауды жалғастыру", - "Continuing": "Жалғасуда", - "Convert": "Түрлендіру", - "ConvertItemLimitHelp": "Міндетті емес: Түрлендірлетін тармақтар саны шегін орнатыңыз.", - "ConvertUnwatchedVideosOnly": "Қаралмаған бейнелерді түрлендіру", - "ConvertUnwatchedVideosOnlyHelp": "Тек қана қаралмаған бейнелер түрлендірледі", - "ConvertingDots": "Түрлендірілуде", - "Countries": "Елдер", - "CriticRating": "Сыншылар бағалауы", - "DateAdded": "Үстелген күні", - "DatePlayed": "Ойнатылған күні", - "Days": "Күндер", - "Default": "Әдепкі", - "DefaultErrorMessage": "Сауал өңделу кезінде қате орын алды. Әрекетті кейін қайталаңыз.", - "DefaultSubtitlesHelp": "Субтитрлер енгізілген метадеректердегі әдепкі және мәжбүрлі жалаушалары негізінде жүктеліп алынады. Бірнеше опция қолжетімді болғанда тіл теңшелімі қарастырылады.", - "Delete": "Жою", - "DeleteMedia": "Тасығышдеректі жою", - "Depressed": "Төмен түсірілген", - "Descending": "Кемуі бойынша", - "Desktop": "Жұмыс үстелі", - "DirectPlayError": "Тікелей ойнату қатесі", - "DirectPlaying": "Тікелей ойнатуда", - "DirectStreamHelp1": "Ажыратымдылық пен тасығышдеректер түріне (H.264, AC3, т.б.) қатысты тасығышдеректер құрылғыға сәйкес келеді, бірақ сыйыспайтын файл контейнерінде (.mkv, .avi, .wmv және т.б.) болып тұр. Құрылғыға таратпас бұрын, бейне нақты уақытта қайта жинақталады.", - "DirectStreamHelp2": "Файлды тікелей тарату бейне сапасын жоғалтпай өте аз есептеу қуатын пайдаланады.", - "DirectStreaming": "Тікелей тасымалдануда", - "Director": "Режиссер", - "DirectorValue": "Режиссері: {0}", - "DirectorsValue": "Режиссерлер; {0}", - "Disc": "Дискі", - "Disconnect": "Ажырату", - "Dislike": "Ұнамайды", - "Display": "Бейнелеу", - "DisplayInMyMedia": "Басты экранда бейнеленеді", - "DisplayInOtherHomeScreenSections": "Басты экран бөлімдерінде бейнелеу (мыс. Ең соңғы тасығышдеректер және Көруді жалғастыру)", - "DisplayMissingEpisodesWithinSeasons": "Жоқ бөлімдерді маусым ішінде бейнелеу", - "DisplayMissingEpisodesWithinSeasonsHelp": "Бұл сондай-ақ Jellyfin Server орнатуындағы ТД тасығышханалары үшін қосулы болуы керек.", - "DisplayModeHelp": "Jellyfin іске қосылғанда экран түрін таңдаңыз.", - "DoNotRecord": "Жазуға болмайды", - "Down": "Төменге", - "Download": "Жүктеп алу", - "DownloadItemLimitHelp": "Міндетті емес: Жүктелетін тармақ санының шегін орнатыңыз.", - "Downloaded": "Жүктеліп алынды", - "Downloading": "Жүктеп алуда", - "DownloadingDots": "Жүктеп алуда...", - "Downloads": "Жүктеулер", - "DownloadsValue": "{0} жүктеу", - "DropShadow": "Көлеңкелі", - "DvrFeatureDescription": "Jellyfin DVR кестесіне жеке эфирлік жазбаларды, топтама жазбаларды, және онан басқаларды енгізіңіз.", - "DvrSubscriptionRequired": "Jellyfin DVR үшін белсенді Jellyfin Premiere жазылымы қажет", - "Edit": "Өңдеу", - "EditImages": "Суреттерді өңдеу", - "EditMetadata": "Метадеректерді өңдеу", - "EditSubtitles": "Субтитрлерді өңдеу", - "EnableBackdrops": "Артқы суреттерді қосу", - "EnableBackdropsHelp": "Қосылғанда, артқы суреттер тасығышхананы шолу кезінде кейбір беттерде өңде бейнеленеді.", - "EnableCinemaMode": "Кинотеатр режімін қосу", - "EnableColorCodedBackgrounds": "Түспен белгіленген өңдерді қосу", - "EnableDisplayMirroring": "Бейнелеудің телнұсқасын қосу", - "EnableExternalVideoPlayers": "Сыртқы ойнатқыштарды қосу", - "EnableExternalVideoPlayersHelp": "Сыртқы ойнатқыш мәзірі бейне ойнатуды бастаған кезде көрсетіледі.", - "EnableNextVideoInfoOverlay": "Ойнату кезінде келесі бейне туралы ақпаратты қосу", - "EnableNextVideoInfoOverlayHelp": "Бейне соңында ағымдағы ойнату тізіміндегі келесі бейне туралы ақпаратты көрсету.", - "EnableThemeSongs": "Тақырыптық әуендерді қосу", - "EnableThemeSongsHelp": "Қосылғанда, тасығышхананы шолу кезінде тақырыптық әуендер өңде ойнатылады.", - "EnableThemeVideos": "Тақырыптық бейнелерді қосу", - "EnableThemeVideosHelp": "Қосылғанда, тасығышхананы шолу кезінде тақырыптық бейнелер өңде ойнатылады.", - "Ended": "Аяқталды", - "EndsAtValue": "Аяқталуы: {0}", - "Episodes": "Бөлімдер", - "Error": "Қате", - "ErrorAddingGuestAccount1": "Jellyfin Connect тіркелгісін үстеу кезінде қате орын алды. Қонағыңыз Jellyfin тіркелгісін жасады ма? Ол {0} жанында тіркелуі мүмкін.", - "ErrorAddingGuestAccount2": "Егер әлі де мәселеңіз болса, өзіңіздің және олардың э-пошта мекенжайларын қосып э-пошта арқылы {0} мекенжайына хабар жіберіңіз.", - "ErrorAddingJellyfinConnectAccount1": "Jellyfin Connect тіркелгісін үстеу кезінде қате орын алды. Jellyfin тіркелгісін жасадыңыз ба? {0} жанында тіркеліңіз.", - "ErrorAddingJellyfinConnectAccount2": "Егер әлі де мәселеңіз болса, Jellyfin тіркелгісінде пайдаланылған э-пошта арқылы {0} мекенжайына хабар жіберіңіз.", - "ErrorConnectServerUnreachable": "Сұралған әрекетті орындауда қате орын алды. Серверіңіз {0} мекенжайындағы Embo Connect Server тарапына қатынаса алмады. Серверде белсенді интернет қосылымы бар екенін және байланыс қай қайсысы брандмауэр немесе орнатылған қауіпсіздік бағдарламалық жасақтама арқылы рұқсат етілуіне көз жеткізіңіз.", - "ErrorDeletingItem": "Jellyfin Server элементін жою кезінде қате орын алды. Jellyfin Server тасығыш қалтасына жазуға рұқсаты бар екенін тексеріп, қайталап көріңіз.", - "ErrorReachingJellyfinConnect": "Jellyfin Connect серверіне жету кезінде қате орын алды. Белсенді интернет қосылымы бар екеніне көз жеткізіңіз және әрекетті кейін қайталаңыз.", - "ErrorRemovingJellyfinConnectAccount": "Jellyfin Connect тіркелгісін аластау кезінде қате орын алды. Белсенді интернет қосылымы бар екеніне көз жеткізіңіз және әрекетті кейін қайталаңыз.", - "ExtraLarge": "Өте ірі", - "Extras": "Қосымшалар", - "Favorite": "Таңдаулы", - "Favorites": "Таңдаулылар", - "FeatureRequiresJellyfinPremiere": "Осы құрамдас үшін белсенді Jellyfin Premiere жазылымы қажет", - "Features": "Ерекшеліктер", - "File": "Файл", - "Fill": "Толтыру", - "Filters": "Сүзгілер", - "Folders": "Қалталар", - "FormatValue": "Пішім: {0}", - "FreeAppsFeatureDescription": "Құрылғыларыңыз үшін Jellyfin-қолданбаларына тегін қатынаңыз.", - "Friday": "жұма", - "GenreValue": "Жанр: {0}", - "Genres": "Жанрлар", - "GenresValue": "Жанрлар: {0}", - "GroupBySeries": "Телехикаялар бойынша топтастыру", - "GroupVersions": "Нұсқаларды топтастыру", - "GuestStar": "Шақырылған актер", - "GuestUserNotFound": "Пайдаланушы табылған жоқ. Атының дұрыстығын тексеріңіз және әрекетті қайталаңыз, немесе оның э-пошта мекенжайын енгізіп көріңіз.", - "Guide": "Телегид", - "HDPrograms": "HD-көрсетімдер", - "HeaderActiveRecordings": "Белсенді жазбалар", - "HeaderAddToCollection": "Жиынтыққа үстеу", - "HeaderAddToPlaylist": "Ойнату тізіміне үстеу", - "HeaderAddUpdateImage": "Суретті үстеу/жаңарту", - "HeaderAlbumArtists": "Альбом орындаушылары", - "HeaderAlreadyPaid": "Әлдеқашан төленді ме?", - "HeaderAppearsOn": "Көруге болады", - "HeaderAudioBooks": "Дыбыстық кітаптар", - "HeaderAudioSettings": "Дыбыс параметрлері", - "HeaderBecomeProjectSupporter": "Jellyfin Premiere алу", - "HeaderBenefitsJellyfinPremiere": "Jellyfin Premiere артықшылықтары", - "HeaderCancelRecording": "Жазуды болдырмау", - "HeaderCancelSeries": "Телехикаяны болдырмау", - "HeaderCinemaMode": "Кинотеатр режімі", - "HeaderCloudSync": "Бұлттық үндестіру", - "HeaderConfirmRecordingCancellation": "Жазу болдырмауын растау", - "HeaderContinueListening": "Тыңдауды жалғастыру", - "HeaderContinueWatching": "Қарауды жалғастыру", - "HeaderConvertYourRecordings": "Жазбаларыңызды түрлендіру", - "HeaderCustomizeHomeScreen": "Басты экранды реттеу", - "HeaderDeleteItem": "Тармақты жою", - "HeaderDeleteItems": "Тармақтарды жою", - "HeaderDisplaySettings": "Бейнелеу параметрлері", - "HeaderDownloadSettings": "Жүктеп алу параметрлері", - "HeaderEditImages": "Суреттерді өңдеу", - "HeaderEnabledFields": "Қосылған өрістер", - "HeaderEnabledFieldsHelp": "Құрсаулау үшін және деректер өзгертуіне тыйым салу үшін, өрістен құсбелгіні алыңыз.", - "HeaderExternalIds": "Сыртқы сәйкестендіргіштер:", - "HeaderFavoriteAlbums": "Таңдаулы альбомдар", - "HeaderFavoriteArtists": "Таңдаулы орындаушылар", - "HeaderFavoriteCollections": "Таңдаулы жиынтықтар", - "HeaderFavoriteEpisodes": "Таңдаулы бөлімдер", - "HeaderFavoriteGames": "Таңдаулы ойындар", - "HeaderFavoriteMovies": "Таңдаулы фильмдер", - "HeaderFavoritePlaylists": "Таңдаулы ойнату тізімдері", - "HeaderFavoriteShows": "Таңдаулы көрсетімдер", - "HeaderFavoriteSongs": "Таңдаулы әуендер", - "HeaderFavoriteVideos": "Тандаулы бейнелер", - "HeaderFreeApps": "Тегін Jellyfin қолданбалары", - "HeaderHomeScreen": "Басты экран", - "HeaderIdentifyItemHelp": "Іздеудің бір не бірнеше шартын енгізіңіз. Іздеу нәтижелерін көбейту үшін шартты аластаңыз.", - "HeaderInvitationSent": "Шақыру жіберілді", - "HeaderJellyfinAccountAdded": "Jellyfin тіркелгісі үстелінді", - "HeaderJellyfinAccountRemoved": "Jellyfin тіркелгісі аласталды", - "HeaderKeepRecording": "Жазуды сақтап қалу", - "HeaderKeepSeries": "Телехикаяны сақтап қалу", - "HeaderLatestChannelItems": "Арналардың ең кейінгі тармақтары", - "HeaderLatestChannelMedia": "Арналардың ең кейінгі тармақтары", - "HeaderLatestFrom": "Ең кейінгі {0}", - "HeaderLatestMedia": "Ең кейінгі тасығышдеректер", - "HeaderLatestRecordings": "Ең кейіңгі жазбалар", - "HeaderLearnMore": "Көбірек білу", - "HeaderLibraryFolders": "Тасығышханалық қалталар", - "HeaderLibraryOrder": "Тасығышхана реті", - "HeaderMetadataSettings": "Метадеректер параметрлері", - "HeaderMusicQuality": "Музыка сапасы", - "HeaderMyDevice": "Менің құрылғым", - "HeaderMyDownloads": "Менің жүктеулерім", - "HeaderMyMedia": "Менің тасығышдеректерім", - "HeaderMyMediaSmall": "Менің тасығышдеректерім (ықшам)", - "HeaderNewRecording": "Жаңа жазба", - "HeaderNextEpisodePlayingInValue": "Келесі бөлім {0} ішінде ойнатылады", - "HeaderNextUp": "Кезекті", - "HeaderNextVideoPlayingInValue": "Келесі бейне {0} ішінде ойнатылады", - "HeaderOfflineDownloads": "Дербес тасығышдерек", - "HeaderOfflineDownloadsDescription": "Оңай дербес қолдану үшін құрылғыларыңызға тасығышдеректерді жүктеп алыңыз.", - "HeaderOnNow": "Эфирде", - "HeaderPhotoAlbums": "Фотоальбомдар", - "HeaderPlayMyMedia": "Менің тасығышдеректерімді ойнату", - "HeaderPlayOn": "Ойнатуды қосу", - "HeaderPlaybackError": "Ойнату қатесі", - "HeaderRecordingOptions": "Жазу опциялары", - "HeaderRemoteControl": "Қашықтан басқару", - "HeaderRestartingJellyfinServer": "Jellyfin Server қайта іске қосылуда", - "HeaderSaySomethingLike": "Осындай сияқтыны айтыңыз...", - "HeaderSecondsValue": "{0} секөнд", - "HeaderSelectDate": "Күнді таңдау", - "HeaderSeriesOptions": "Телехикая опциялары", - "HeaderSeriesStatus": "Телехикая күйі", - "HeaderSpecialEpisodeInfo": "Арнайы бөлім туралы", - "HeaderStartNow": "Қазір бастау", - "HeaderStopRecording": "Жазуды тоқтату", - "HeaderSubtitleAppearance": "Субтитрлер көрінісі", - "HeaderSubtitleSettings": "Субтитрлер параметрлері", - "HeaderSyncRequiresSub": "Жүктеп алу үшін белсенді Jellyfin Premiere жазылымы қажет", - "HeaderTermsOfPurchase": "Сатып алу шарттары", - "HeaderTryPlayback": "Ойнатуды сынап көріңіз", - "HeaderUnlockFeature": "Артықшылық құрсауын босату", - "HeaderUploadImage": "Суретті жүктеп беру", - "HeaderVideoQuality": "Бейне сапасы", - "HeaderVideoType": "Бейне түрі", - "HeaderWaitingForWifi": "WiFi үшін күтуде", - "HeaderWakeServer": "Серверді ояту", - "HeaderYouSaid": "Сіз айтқаныңыз...", - "Help": "Интернеттегі анықтамаға", - "Hide": "Жасыру", - "HideWatchedContentFromLatestMedia": "Ең кейінгі тасығышдеректерден қаралған мазмұнды жасыру", - "Home": "Басты", - "Horizontal": "Көлденең", - "HowDidYouPay": "Қалай төледіңіз?", - "IHaveJellyfinPremiere": "Менде Jellyfin Premiere бар", - "IPurchasedThisApp": "Мен осы қолданбаны сатып алдым", - "Identify": "Анықтау", - "Images": "Суреттер", - "ImdbRating": "IMDb бағалауы", - "InstallingPackage": "{0} орнатылуда", - "InstantMix": "Лездік қоспалау", - "InterlacedVideoNotSupported": "Кезектесулік бейне үшін қолдау көрсетілмейді", - "ItemCount": "{0} тармақ", - "Items": "Тармақтар", - "KeepDownload": "Жүктеуді сақтап қалу", - "KeepOnDevice": "Құрылғыда сақтап қалу", - "Kids": "Балалық", - "Label3DFormat": "3D пішімі:", - "LabelAirDays": "Эфир күндері:", - "LabelAirTime": "Эфир уақыты:", - "LabelAirsAfterSeason": "\"Airs after\" маусымы", - "LabelAirsBeforeEpisode": "\"Airs after\" бөлімі", - "LabelAirsBeforeSeason": "\"Airs before\" маусымы", - "LabelAlbum": "Альбом:", - "LabelAlbumArtists": "Альбом орындаушылары:", - "LabelArtists": "Орындаушылар:", - "LabelArtistsHelp": "Бірнешуін (;) арқылы бөліңіз", - "LabelAudio": "Дыбыс:", - "LabelAudioLanguagePreference": "Дыбыс тілінің теңшелімі:", - "LabelBirthDate": "Туған күні:", - "LabelBirthYear": "Туған жылы:", - "LabelBitrateMbps": "Қарқыны (Мбит/с):", - "LabelBurnSubtitles": "Субтитрлерді жазу:", - "LabelChannels": "Арналар:", - "LabelCollection": "Жиынтық:", - "LabelCommunityRating": "Қауым бағалауы:", - "LabelContentType": "Мазмұн түрі:", - "LabelConvertTo": "Мынаған түрлендіру:", - "LabelCountry": "Ел:", - "LabelCriticRating": "Сыншылар бағалауы:", - "LabelCustomRating": "Теңшелген санат:", - "LabelDashboardTheme": "Сервер тақтасының тақырыбы:", - "LabelDateAdded": "Үстелген күні", - "LabelDateTimeLocale": "Күн мен уақыт:", - "LabelDeathDate": "Өлген күні:", - "LabelDefaultScreen": "Әдепкі экран:", - "LabelDiscNumber": "Дискі нөмірі:", - "LabelDisplayLanguage": "Бейнелеу тілі:", - "LabelDisplayLanguageHelp": "Jellyfin тәржімелеуі ағымдағы жоба болып табылады.", - "LabelDisplayMode": "Бейнелеу режімі:", - "LabelDisplayOrder": "Бейнелеу реті:", - "LabelDropImageHere": "Суретті мұнда сүйретіңіз немесе шарлау үшін нұқыңыз.", - "LabelDropShadow": "Жиектер:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "Э-пошта мекенжайы:", - "LabelEndDate": "Аяқталу күні:", - "LabelEpisodeNumber": "Бөлім нөмірі:", - "LabelFont": "Қаріп:", - "LabelHomeNetworkQuality": "Үйлік желі сапасы:", - "LabelHomeScreenSectionValue": "Басты бет {0}-бөлім:", - "LabelImageType": "Сурет түрі:", - "LabelInternetQuality": "Интернеттегі сапасы:", - "LabelItemLimit": "Тармақтар шегі:", - "LabelKeep:": "Сақтап қалу:", - "LabelKeepUpTo": "Осыған дейін сақтап қалу:", - "LabelLanguage": "Тіл:", - "LabelLockItemToPreventChanges": "Осы тармақты келешек өзгертулерден құрсаулау", - "LabelMaxChromecastBitrate": "Chromecast тасымалдану сапасы:", - "LabelMetadataDownloadLanguage": "Жүктеп алу тілінің теңшелімі:", - "LabelName": "Аты:", - "LabelNumber": "Нөмірі:", - "LabelOriginalAspectRatio": "Бастапқы пішімдік арақатынасы:", - "LabelOriginalTitle": "Бастапқы атауы:", - "LabelOverview": "Жалпы шолу:", - "LabelParentNumber": "Тектік нөмір:", - "LabelParentalRating": "Жастас санаты:", - "LabelPath": "Жолы:", - "LabelPersonRole": "Рөлі:", - "LabelPersonRoleHelp": "Мысал: Балмұздақ фургонының жүргізушісі", - "LabelPlaceOfBirth": "Туған жері:", - "LabelPlayDefaultAudioTrack": "Тілге қатыссыз әдепкі дыбыс жолшығын ойнату", - "LabelPlaylist": "Ойнату тізімі:", - "LabelPreferredSubtitleLanguage": "Субтитр тілінің теңшелімі:", - "LabelProfile": "Профайл:", - "LabelQuality": "Сапасы:", - "LabelReasonForTranscoding": "Қайта кодтау себебі:", - "LabelRecord": "Жазу:", - "LabelRefreshMode": "Жаңғырту режімі:", - "LabelReleaseDate": "Шығару күні:", - "LabelRuntimeMinutes": "Ұзақтығы, мин:", - "LabelScreensaver": "Экран қорғауыш:", - "LabelSeasonNumber": "Маусым нөмірі:", - "LabelSelectFolderGroups": "Келесі қалталардағы мазмұнды Кино, Музыка және ТД сияқты аспекттерге автоматты түрде топтастыру:", - "LabelSelectFolderGroupsHelp": "Белгіленбеген қалталар өз бетімен өзінің аспектінде бейнеленеді.", - "LabelShortOverview": "Қысқаша шолу:", - "LabelSkin": "Мұқаба:", - "LabelSkipBackLength": "Артқа өткізіп жіберу ұзақтығы:", - "LabelSkipForwardLength": "Алға өткізіп жіберу ұзақтығы:", - "LabelSortBy": "Сұрыптау тәсілі:", - "LabelSortOrder": "Сұрыптау реті:", - "LabelSortTitle": "Атау бойынша сұрыптау", - "LabelSoundEffects": "Дыбыстық әсерлері:", - "LabelSource": "Қайнар көзі:", - "LabelStartWhenPossible": "Мүмкіндік болғанда бастау:", - "LabelStatus": "Күй:", - "LabelStopWhenPossible": "Мүмкіндік болғанда тоқтату:", - "LabelSubtitlePlaybackMode": "Субтитр режімі:", - "LabelSubtitles": "Субтитрлер:", - "LabelSyncJobName": "Үндестіру жұмысының аты:", - "LabelSyncNoTargetsHelp": "Жүктеп алуды қолдайтын қайбір қолданба ағымда табылмамаған болып көрінеді.", - "LabelSyncTo": "Осымен үндестіру:", - "LabelTVHomeScreen": "ТД режіміндегі басты экран:", - "LabelTagline": "Негізгі сөйлем:", - "LabelTextBackgroundColor": "Мәтін өңінің түсі:", - "LabelTextColor": "Мәтін түсі:", - "LabelTextSize": "Мәтін өлшемі:", - "LabelTheme": "Тақырып:", - "LabelTitle": "Атауы:", - "LabelTrackNumber": "Жолшық нөмірі:", - "LabelType": "Түрі:", - "LabelVersion": "Нұсқа:", - "LabelVideo": "Бейне:", - "LabelWebsite": "Ғаламтор сайты:", - "LabelWindowBackgroundColor": "Терезе өңінің түсі:", - "LabelYear": "Жыл:", - "Large": "Ірі", - "LatestFromLibrary": "Ең кейінгі {0}", - "LearnHowYouCanContribute": "Қалай үлес қосуыныңыз мүмкін туралы үйреніңіз.", - "LearnMore": "Көбірек білу", - "Like": "Ұнайды", - "LinksValue": "Сілтемелер: {0}", - "List": "Тізім", - "Live": "Тікелей", - "LiveBroadcasts": "Тікелей таратымдар", - "LiveTV": "Эфир", - "LiveTvFeatureDescription": "Jellyfin Server орнатылған үйлесімді ТД-тюнер құрылғысы арқылы кез келген Jellyfin-қолданбаға ТД-эфирді тікелей жіберу.", - "LiveTvRequiresUnlock": "Эфирлік ТД үшін белсенді Jellyfin Premiere жазылымы қажет", - "Logo": "Логотип", - "ManageRecording": "Жазуды реттеу", - "MarkPlayed": "Ойнатылған деп белгілеу", - "MarkUnplayed": "Ойнатылмаған деп белгілеу", - "MarkWatched": "Қарап шыққан", - "MediaIsBeingConverted": "Тасығышдеректер ойнатушы құрылғымен үйлесімді пішімге түрлендіріледі.", - "Medium": "Орташа", - "Menu": "Мәзір", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Телехикаялардың автоматты жазбасын жасау үшін белсенді Jellyfin Premiere жазылымы қажет.", - "MessageAreYouSureDeleteSubtitles": "Шынымен осы субтитрлер файлын жою қажет пе?", - "MessageConfirmRecordingCancellation": "Жазуды болдырмау қажет пе?", - "MessageDownloadQueued": "Жүктеп алу кезекте.", - "MessageFileReadError": "Файл оқу кезінде қате орын алды. Әрекетті кейін қайталаңыз.", - "MessageIfYouBlockedVoice": "Егер қолданбаға дауыстық қатынаудан бас тартсаңыз, қайта әрекеттенуіңізден алдынан қайта теңшеуіңіз қажет болады.", - "MessageInvitationSentToNewUser": "Jellyfin үшін тіркелу шақыруыңыз, э-пошта {0} үшін жіберілді.", - "MessageInvitationSentToUser": "Оларға ортақтасу шақыруыңызды қабылдау ұсынысымен, э-пошта {0} арнап жіберілді.", - "MessageItemSaved": "Тармақ сақталды.", - "MessageItemsAdded": "Тармақтар үстелген.", - "MessageJellyfinAccontRemoved": "Jellyfin тіркелгісі осы пайдаланушыдан аласталынды.", - "MessageJellyfinAccountAdded": "Jellyfin тіркелгісі осы пайдаланушыга үстелінді.", - "MessageLeaveEmptyToInherit": "Тектік тармақтан, немесе ғаламдық әдепкі мәнінені. параметрлер мұрасына иелену үшін бос қалдырыңыз.", - "MessageNoDownloadsFound": "Дербес жүктеулер жоқ. Бүкіл қолданбадағы Жүктеу түймешігін басып дербес қолдану үшін тасығышдеректерді жүктеп алыңыз.", - "MessageNoServersAvailableToConnect": "Қосылу үшін ешқандай серверлер қол жетімді емес. Егер сервермен ортақтасуға шақырылсаңыз, қабылдауын төменде немесе э-поштадағы сілтемені нұқып нақтылаңыз.", - "MessageNoSyncJobsFound": "Жүктеулер табылмады. Бүкіл қолданбадағы Жүктеу түймешіктерін пайдаланып жүктеуу жұмыстарын жасаңыз.", - "MessagePendingJellyfinAccountAdded": "Jellyfin тіркелгісі осы пайдаланушыга үстелінді. Тіркелгі иесіне э-пошта жіберіледі. Э-поштадағы сілтемені нұқып шақыруды растау қажет болады.", - "MessagePlayAccessRestricted": "Осы мазмұндың ойнатуы ағымда шектелген. Қосымша ақпарат алу үшін Jellyfin Server әкімшісіне байланысыңыз.", - "MessageToValidateSupporter": "Егер сізде белсенді Jellyfin Premiere жазылымы болса, Jellyfin Server тақтасындағы Jellyfin Premiere орнатылып теңшелгеніне көз жеткізіңіз. Бұл басты мәзірде Jellyfin Premiere дегенді нұқып қатынаулы.", - "MessageUnlockAppWithPurchaseOrSupporter": "Осы құрамдасты бір жолғы сатып алу, немесе белсенді Jellyfin Premiere жазылымы арқылы құрсаудан босату.", - "MessageUnlockAppWithSupporter": "Осы құрамдасты белсенді Jellyfin Premiere жазылымы арқылы құрсаудан босату.", - "MessageWeDidntRecognizeCommand": "Осындай пәрменді танып айырмадық.", - "MinutesAfter": "минут соңыңда", - "MinutesBefore": "минут алдында", - "Mobile": "Ұялы / Планшеттік", - "Monday": "дүйсенбі", - "More": "Көбірек", - "MoveLeft": "Солға жылжыту", - "MoveRight": "Оңға жылжыту", - "Movies": "Фильмдер", - "MySubtitles": "Менің субтитрлерім", - "Name": "Аты", - "NewCollection": "Жаңа жиынтық", - "NewCollectionHelp": "Жиынтықтар сізге Фильмдердің және тағы басқа тасығышхананың мазмұнын дербестендірілген топтауларымен тамашалану үшін рұқсат етеді.", - "NewCollectionNameExample": "Мысал: Жұлдыз соғыстары (жиынтық)", - "NewEpisodes": "Жаңа бөлімдер", - "NewEpisodesOnly": "Тек қана жаңа бөлімдерді", - "News": "Жаңалық", - "Next": "Келесі", - "No": "Жоқ", - "NoItemsFound": "Ешқандай тармақтар табылмады.", - "NoSubtitleSearchResultsFound": "Ешқандай нәтижелер табылмады.", - "NoSubtitles": "Субтитрлерсіз", - "NoSubtitlesHelp": "Әдепкіде субтитрлер жүктелмейді. Оларды ойнату кезінде әлі де қолмен қосуға болады.", - "None": "Ешқандай", - "Normal": "Кәдімгі", - "Off": "Өшір", - "OneChannel": "Бір арнадан", - "OnlyForcedSubtitles": "Тек қана мәжбүрлі субтитрлер", - "OnlyForcedSubtitlesHelp": "Тек қана мәжбүрлі деп белгіленген субтитрлер жүктеледі.", - "OnlyImageFormats": "Тек кескін пішімдері (VOBSUB, PGS, SUB/IDX және т.б. )", - "Open": "Ашу", - "OptionNew": "Жаңа...", - "Original": "Түпнұсқалы", - "OriginalAirDateValue": "Бастапқы эфир: {0}", - "Overview": "Жалпы шолу", - "PackageInstallCancelled": "{0} орнатылуы болдырылмады.", - "PackageInstallCompleted": "{0} орнатылуы аяқталды.", - "PackageInstallFailed": "{0} орнатылуы сәтсіз.", - "ParentalRating": "Жастас санаты", - "People": "Адамдар", - "PerfectMatch": "Үздік тең", - "Photos": "Фотосуреттер", - "PlaceFavoriteChannelsAtBeginning": "Таңдаулы арналарды ең басынан орналастыру", - "Play": "Ойнату", - "PlayAllFromHere": "Бұл арадан бәрін ойнату", - "PlayCount": "Ойнату есебі", - "PlayFromBeginning": "Басынан ойнату", - "PlayNext": "Келесіні ойнату", - "PlayNextEpisodeAutomatically": "Келесі бөлімді автоматты түрде жүктеп алу", - "PlaybackErrorNoCompatibleStream": "Ағымда ешқандай сыйысымды ағындар қолжетімді емес. Әрекетті кейін қайталаңыз немесе толық мәліметтер үшін жүйелік әкімшіңізге байланысыңыз.", - "PlaybackErrorNotAllowed": "Осы мазмұнды ойнату үшін ағымда сізге рұқсат етілмеген. Толық мәліметтер үшін жүйелік әкімшіңізге байланысыңыз.", - "PlaybackErrorPlaceHolder": "Осы бейнені ойнату үшін дискіні енгізіңіз.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "Әдепкі ойнату параметрлерін теңшеу үшін бейне ойнатуды тоқтатыңыз, содан кейін қолданбаның жоғарғы оң жақ бөлігіндегі пайдаланушы белгішесін басыңыз.", - "Played": "Ойнатылған", - "Playlists": "Ойнату тізімдері", - "PleaseEnterNameOrId": "Атын немесе сыртқы ID енгізіңіз.", - "PleaseRestartServerName": "Jellyfin Server үшін қайта іске қосыңыз - {0}.", - "PleaseSelectDeviceToSyncTo": "Қайда жүктелетін құрылғыны таңдаңыз.", - "PleaseSelectTwoItems": "Ең кемінде екі тармақты таңдаңыз.", - "Premiere": "Тұсаукесері", - "Premieres": "Премьералар", - "Previous": "Алдыңғы", - "Primary": "Негізгі", - "PrivacyPolicy": "Құпиялылық саясаты", - "Producer": "Продюсер", - "ProductionLocations": "Өндіру орындары", - "Programs": "Көрсетімдер", - "PromoConvertRecordingsToStreamingFormat": "Jellyfin Premiere арқылы тасымалдауға оңай пішінде жазбаларды автоматты түрде түрлендіру. Жазбалар Jellyfin Server параметрлері негізінде, нақты уақытта MP4 немесе MKV пішіміне түрлендіріледі.", - "Quality": "Сапасы", - "QueueAllFromHere": "Бұл арадан бәрін кезекке", - "Raised": "Көтерілген", - "RecentlyWatched": "Жуықта қаралған", - "Record": "Жазу", - "RecordSeries": "Телехикаяны жазу", - "RecordingCancelled": "Жазба болдырылмады.", - "RecordingScheduled": "Жазу жоспарлаған.", - "Recordings": "Жазбалар", - "RefFramesNotSupported": "Бейненің тірек кадрлар санына қолдау көрсетілмейді", - "Refresh": "Жаңғырту", - "RefreshDialogHelp": "Метадеректер параметрлер мен Jellyfin Server тақтасында қосылған интернет қызметтері негізінде жаңғыртылады.", - "RefreshMetadata": "Метадеректерді жаңғырту", - "RefreshQueued": "Жаңғырту кезекте.", - "Reject": "Қабылдамау", - "ReleaseDate": "Шығару кезі", - "RemoveDownload": "Жүктеуді аластау", - "RemoveFromCollection": "Жиынтықтан аластау", - "RemoveFromPlaylist": "Ойнату тізімінен аластау", - "RemovingFromDevice": "Құрылғыдан аластауда", - "Repeat": "Қайталау", - "RepeatAll": "Барлығын қайталау", - "RepeatEpisodes": "Бөлімдердің қайталануы", - "RepeatMode": "Қайталау режімі", - "RepeatOne": "Бір рет қайталау", - "ReplaceAllMetadata": "Барлық метадеректерді ауыстыру", - "ReplaceExistingImages": "Бар суреттерді ауыстыру", - "RestartPleaseWaitMessage": "Jellyfin Server жұмысы аяқталып, қайта іске қосылғанша дейін күте тұрыңыз. Бұл бір-екі минөтқа созылуы мүмкін.", - "ResumeAt": "{0} бастап жалғастыру", - "Retry": "Қайталау", - "RunAtStartup": "Іске қосылудан бастап орындау", - "Runtime": "Ұзақтығы", - "Saturday": "сенбі", - "Save": "Сақтау", - "ScanForNewAndUpdatedFiles": "Жаңа және жаңартылған файлдарды сканерлеу", - "Schedule": "Іс кестесі", - "Screenshot": "Экран суреті", - "Screenshots": "Экран суреттері", - "Search": "Іздеу", - "SearchForCollectionInternetMetadata": "Суреттемелер бен метадеректерді Интернеттен іздеу", - "SearchForMissingMetadata": "Жоқ метадеректерді іздеу", - "SearchForSubtitles": "Субтитрлерді іздеу", - "SearchResults": "Іздеу нәтижелері", - "SecondaryAudioNotSupported": "Дыбыс жолшығын ауыстыру үшін қолдау көрсетілмейді", - "SeriesCancelled": "Телехикая болдырылмады.", - "SeriesDisplayOrderHelp": "Бөлімдерді эфир күнімен, DVD ретімен немесе түпнұсқалық нөмірлеуімен реттеу.", - "SeriesRecordingScheduled": "Телехикая жазуы жоспарлаған.", - "SeriesSettings": "Телехикая параметрлері", - "SeriesYearToPresent": "{0} - қазірде", - "ServerNameIsRestarting": "Jellyfin Server - {0} қайта іске қосылуда.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} жұмысын аяқтауда.", - "ServerUpdateNeeded": "Осы Jellyfin Server жаңартылуы қажет. Соңғы нұсқасын жүктеп алу үшін, {0} кіріңіз", - "Settings": "Параметрлер", - "SettingsSaved": "Параметрлер сақталды.", - "Share": "Ортақтасу", - "ShowIndicatorsFor": "Мынау үшін белгі көрсету:", - "ShowTitle": "Көрсетім атауы", - "ShowYear": "Көрсетім жылы", - "Shows": "Көрсетімдер", - "Shuffle": "Араластыру", - "SkipEpisodesAlreadyInMyLibrary": "Менің тасығышханамда бар бөлімдерді жазбау", - "SkipEpisodesAlreadyInMyLibraryHelp": "Қол жетімді болғанда, бөлімдер маусым және бөлім нөмірлері бойынша салыстырылады.", - "Small": "Ұсақ", - "SmallCaps": "Кіші бас әріптер", - "Smaller": "Кішігірім", - "Smart": "Зиятты", - "SmartSubtitlesHelp": "Тіл теңшеліміне сәйкес келген субтитрлер дыбыс шетел тілінде болғанда жүктеледі.", - "Songs": "Әуендер", - "Sort": "Сұрыптау", - "SortByValue": "Сұрыптау тәсілі {0}", - "SortChannelsBy": "Арналарды сұрыптау тәсілі:", - "SortName": "Сұрыпталатын аты", - "Sports": "Спорт", - "StatsForNerds": "Ақылгөйлер үшін санақ", - "StopRecording": "Жазуды тоқтату", - "Studios": "Студиялар", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Бұл параметрлер осы құрылғы арқылы іске қосылған кез-келген Chromecast ойнатуына қолданылады.", - "SubtitleAppearanceSettingsDisclaimer": "Бұл параметрлер графикалық субтитрлерге (PGS, DVD ж.т.б.) немесе өз мәнері бар ендірілген субтитрлерге (ASS/SSA) қолданылмайды.", - "SubtitleCodecNotSupported": "Субтитрлер пішім үшін қолдау көрсетілмейді", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "Әдепкі субтитр көрінісін және тіл параметрлерін теңшеу үшін бейне ойнатуды тоқтатыңыз, содан кейін қолданбаның жоғарғы оң жақ бөлігіндегі пайдаланушы белгішесін басыңыз.", - "Subtitles": "Субтитрлер", - "Suggestions": "Ұсыныстар", - "Sunday": "жексенбі", - "Sync": "Үндестіру", - "SyncJobItemStatusCancelled": "Болдырылмады", - "SyncJobItemStatusConverting": "Түрлендіруде", - "SyncJobItemStatusFailed": "Сәтсіз", - "SyncJobItemStatusQueued": "Кезекте", - "SyncJobItemStatusReadyToTransfer": "Ауыстырылуға дайын", - "SyncJobItemStatusRemovedFromDevice": "Құрылғыдан аласталған", - "SyncJobItemStatusSynced": "Жүктеліп алынды", - "SyncJobItemStatusSyncedMarkForRemoval": "Құрылғыдан аластауда", - "SyncJobItemStatusTransferring": "Ауыстырылуда", - "SyncUnwatchedVideosOnly": "Қаралмаған бейнелерді жүктеу", - "SyncUnwatchedVideosOnlyHelp": "Тек қана қаралмаған бейнелер жүктеледі, қаралғаннан кейін құр-дан аласталады.", - "SyncingDots": "Үндестрілуде", - "TV": "ТД", - "Tags": "Тегтер", - "TagsValue": "Тегтер: {0}", - "TermsOfUse": "Пайдалану шарттары", - "ThankYouForTryingEnjoyOneMinute": "Бір минөт ойнатуды тамашалаңыз. Jellyfin сынап көргеніңізге рақмет.", - "ThemeSongs": "Тақырыптық әуендер", - "ThemeVideos": "Тақырыптық бейнелер", - "TheseSettingsAffectSubtitlesOnThisDevice": "Бұл параметрлер осы құрылғыдағы субтитрлерге әсер етеді", - "Thumb": "Нобай", - "Thursday": "бейсенбі", - "TrackCount": "{0} жолшық", - "Trailer": "Трейлер", - "Trailers": "Трейлерлер", - "Transcoding": "Қайта кодтауда", - "TryMultiSelect": "Үндескен бөлектеуді сынап көру", - "TryMultiSelectMessage": "Бірнеше тасығыш деректер элементтерін өңдеу үшін, кез келген постерді жай ғана тінтуір батырмаға басып тұрып нұқыңыз және басқаруын қалаған элементтерді бөлектеңіз. Сынап көріңіз!", - "Tuesday": "сейсенбі", - "Uniform": "Бірыңғай", - "UnlockGuide": "Телегидті құрсаудан босату", - "Unplayed": "Ойнатылмаған", - "Unrated": "Бағаланбаған", - "UntilIDelete": "Мен жойғанша дейін", - "UntilSpaceNeeded": "Орын керек болғанша дейін", - "Up": "Жоғарыға", - "Upload": "Кері қотару", - "ValueAlbumCount": "{0} альбом", - "ValueDiscNumber": "{0}-дискі", - "ValueEpisodeCount": "{0} бөлім", - "ValueGameCount": "{0} ойын", - "ValueMinutes": "{0} мин", - "ValueMovieCount": "{0} фильм", - "ValueMusicVideoCount": "{0} музыкалық бейне", - "ValueOneAlbum": "1 альбом", - "ValueOneEpisode": "1 бөлім", - "ValueOneGame": "1 ойын", - "ValueOneItem": "1 тармақ", - "ValueOneMovie": "1 фильм", - "ValueOneMusicVideo": "1 музыкалық бейне", - "ValueOneSeries": "1 телехикая", - "ValueOneSong": "1 әуен", - "ValueSeconds": "{0} сек", - "ValueSeriesCount": "{0} телехикая", - "ValueSongCount": "{0} әуен", - "ValueSpecialEpisodeName": "Арнайы - {0}", - "Vertical": "Тігінен", - "VideoBitDepthNotSupported": "Бейненің биттік тереңдігі үшін қолдау көрсетілмейді", - "VideoCodecNotSupported": "Бейне кодек үшін қолдау көрсетілмейді", - "VideoFramerateNotSupported": "Бейненің кадр жылдамдығы үшін қолдау көрсетілмейді", - "VideoLevelNotSupported": "Бейне деңгейі үшін қолдау көрсетілмейді", - "VideoProfileNotSupported": "Бейне профайлы үшін қолдау көрсетілмейді", - "VideoRange": "Бейне ауқымы", - "VideoResolutionNotSupported": "Бейне ажыратылымдығы үшін қолдау көрсетілмейді", - "ViewAlbum": "Альбомды қарау", - "ViewArtist": "Орындаушыны қарау", - "VoiceInput": "Дауыстық енгізу", - "WakeServer": "Серверді ояту", - "WakeServerError": "Wake On LAN пакеттері сіздің серверіңізге жіберілді, бірақ сіздің Jellyfin Server үшін қосыла алмаймыз. Құрылғыңызды ояту үшін біраз уақыт қажет болуы мүмкін немесе Jellyfin Server құрылғыда белсенді жұмыс істемеуі мүмкін.", - "WakeServerSuccess": "Сәттілік!", - "Watched": "Қаралған", - "Wednesday": "сәрсенбі", - "WifiRequiredToDownload": "Жүктеп алуды жалғастыру үшін WiFi қосылымы қажет.", - "Writer": "Сценарийші", - "Yes": "Иә" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "\u041e\u0441\u044b \u049b\u04b1\u0440\u0430\u043c\u0434\u0430\u0441\u0442\u044b \u0431\u0456\u0440 \u0436\u043e\u043b\u0493\u044b \u0441\u0430\u0442\u044b\u043f \u0430\u043b\u0443, \u043d\u0435\u043c\u0435\u0441\u0435 \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 Emby Premiere \u0436\u0430\u0437\u044b\u043b\u044b\u043c\u044b \u0430\u0440\u049b\u044b\u043b\u044b \u049b\u04b1\u0440\u0441\u0430\u0443\u0434\u0430\u043d \u0431\u043e\u0441\u0430\u0442\u0443.", + "MessageUnlockAppWithSupporter": "\u041e\u0441\u044b \u049b\u04b1\u0440\u0430\u043c\u0434\u0430\u0441\u0442\u044b \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 Emby Premiere \u0436\u0430\u0437\u044b\u043b\u044b\u043c\u044b \u0430\u0440\u049b\u044b\u043b\u044b \u049b\u04b1\u0440\u0441\u0430\u0443\u0434\u0430\u043d \u0431\u043e\u0441\u0430\u0442\u0443.", + "MessageToValidateSupporter": "\u0415\u0433\u0435\u0440 \u0441\u0456\u0437\u0434\u0435 \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 Emby Premiere \u0436\u0430\u0437\u044b\u043b\u044b\u043c\u044b \u0431\u043e\u043b\u0441\u0430, Emby Server \u0442\u0430\u049b\u0442\u0430\u0441\u044b\u043d\u0434\u0430\u0493\u044b Emby Premiere \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u044b\u043f \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d\u0456\u043d\u0435 \u043a\u04e9\u0437 \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u04a3\u0456\u0437. \u0411\u04b1\u043b \u0431\u0430\u0441\u0442\u044b \u043c\u04d9\u0437\u0456\u0440\u0434\u0435 Emby Premiere \u0434\u0435\u0433\u0435\u043d\u0434\u0456 \u043d\u04b1\u049b\u044b\u043f \u049b\u0430\u0442\u044b\u043d\u0430\u0443\u043b\u044b.", + "ValueSpecialEpisodeName": "\u0410\u0440\u043d\u0430\u0439\u044b - {0}", + "Share": "\u041e\u0440\u0442\u0430\u049b\u0442\u0430\u0441\u0443", + "Add": "\u04ae\u0441\u0442\u0435\u0443", + "ServerUpdateNeeded": "\u041e\u0441\u044b Emby Server \u0436\u0430\u04a3\u0430\u0440\u0442\u044b\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442. \u0421\u043e\u04a3\u0493\u044b \u043d\u04b1\u0441\u049b\u0430\u0441\u044b\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443 \u04af\u0448\u0456\u043d, {0} \u043a\u0456\u0440\u0456\u04a3\u0456\u0437", + "LiveTvRequiresUnlock": "\u042d\u0444\u0438\u0440\u043b\u0456\u043a \u0422\u0414 \u04af\u0448\u0456\u043d \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 Emby Premiere \u0436\u0430\u0437\u044b\u043b\u044b\u043c\u044b \u049b\u0430\u0436\u0435\u0442", + "AttributeNew": "\u0416\u0430\u04a3\u0430", + "Premiere": "\u0422\u04b1\u0441\u0430\u0443\u043a\u0435\u0441\u0435\u0440\u0456", + "Live": "\u0422\u0456\u043a\u0435\u043b\u0435\u0439", + "Repeat": "\u049a\u0430\u0439\u0442\u0430\u043b\u0430\u0443", + "TrackCount": "{0} \u0436\u043e\u043b\u0448\u044b\u049b", + "ItemCount": "{0} \u0442\u0430\u0440\u043c\u0430\u049b", + "OriginalAirDateValue": "\u0411\u0430\u0441\u0442\u0430\u043f\u049b\u044b \u044d\u0444\u0438\u0440: {0}", + "EndsAtValue": "\u0410\u044f\u049b\u0442\u0430\u043b\u0443\u044b: {0}", + "HeaderSelectDate": "\u041a\u04af\u043d\u0434\u0456 \u0442\u0430\u04a3\u0434\u0430\u0443", + "Watched": "\u049a\u0430\u0440\u0430\u043b\u0493\u0430\u043d", + "AirDate": "\u042d\u0444\u0438\u0440 \u043a\u04af\u043d\u0456", + "Played": "\u041e\u0439\u043d\u0430\u0442\u044b\u043b\u0493\u0430\u043d", + "ButtonOk": "\u0416\u0430\u0440\u0430\u0439\u0434\u044b", + "ButtonCancel": "\u0411\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443", + "AccessRestrictedTryAgainLater": "\u0410\u0493\u044b\u043c\u0434\u0430 \u049b\u0430\u0442\u044b\u043d\u0430\u0443 \u0448\u0435\u043a\u0442\u0435\u043b\u0433\u0435\u043d. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.", + "ButtonGotIt": "\u0422\u04af\u0441\u0456\u043d\u0456\u043a\u0442\u0456", + "ButtonRestart": "\u049a\u0430\u0439\u0442\u0430 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u0443", + "RecordingCancelled": "\u0416\u0430\u0437\u0431\u0430 \u0431\u043e\u043b\u0434\u044b\u0440\u044b\u043b\u043c\u0430\u0434\u044b.", + "SeriesCancelled": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f \u0431\u043e\u043b\u0434\u044b\u0440\u044b\u043b\u043c\u0430\u0434\u044b.", + "RecordingScheduled": "\u0416\u0430\u0437\u0443 \u0436\u043e\u0441\u043f\u0430\u0440\u043b\u0430\u0493\u0430\u043d.", + "SeriesRecordingScheduled": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f \u0436\u0430\u0437\u0443\u044b \u0436\u043e\u0441\u043f\u0430\u0440\u043b\u0430\u0493\u0430\u043d.", + "HeaderNewRecording": "\u0416\u0430\u04a3\u0430 \u0436\u0430\u0437\u0431\u0430", + "WakeServer": "\u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0456 \u043e\u044f\u0442\u0443", + "HeaderWakeServer": "\u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0456 \u043e\u044f\u0442\u0443", + "AttemptingWakeServer": "\u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0456 \u043e\u044f\u0442\u0443 \u04d9\u0440\u0435\u043a\u0435\u0442\u0456 \u0436\u0430\u0441\u0430\u043b\u0443\u0434\u0430. \u041a\u04af\u0442\u0435 \u0442\u04b1\u0440\u044b\u04a3\u044b\u0437...", + "WakeServerSuccess": "\u0421\u04d9\u0442\u0442\u0456\u043b\u0456\u043a!", + "HeaderCustomizeHomeScreen": "\u0411\u0430\u0441\u0442\u044b \u044d\u043a\u0440\u0430\u043d\u0434\u044b \u0440\u0435\u0442\u0442\u0435\u0443", + "WakeServerError": "Wake On LAN \u043f\u0430\u043a\u0435\u0442\u0442\u0435\u0440\u0456 \u0441\u0456\u0437\u0434\u0456\u04a3 \u0441\u0435\u0440\u0432\u0435\u0440\u0456\u04a3\u0456\u0437\u0433\u0435 \u0436\u0456\u0431\u0435\u0440\u0456\u043b\u0434\u0456, \u0431\u0456\u0440\u0430\u049b \u0441\u0456\u0437\u0434\u0456\u04a3 Emby Server \u04af\u0448\u0456\u043d \u049b\u043e\u0441\u044b\u043b\u0430 \u0430\u043b\u043c\u0430\u0439\u043c\u044b\u0437. \u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u04a3\u044b\u0437\u0434\u044b \u043e\u044f\u0442\u0443 \u04af\u0448\u0456\u043d \u0431\u0456\u0440\u0430\u0437 \u0443\u0430\u049b\u044b\u0442 \u049b\u0430\u0436\u0435\u0442 \u0431\u043e\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d \u043d\u0435\u043c\u0435\u0441\u0435 Emby Server \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430 \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 \u0436\u04b1\u043c\u044b\u0441 \u0456\u0441\u0442\u0435\u043c\u0435\u0443\u0456 \u043c\u04af\u043c\u043a\u0456\u043d.", + "Sunday": "\u0436\u0435\u043a\u0441\u0435\u043d\u0431\u0456", + "Monday": "\u0434\u04af\u0439\u0441\u0435\u043d\u0431\u0456", + "Tuesday": "\u0441\u0435\u0439\u0441\u0435\u043d\u0431\u0456", + "Wednesday": "\u0441\u04d9\u0440\u0441\u0435\u043d\u0431\u0456", + "Thursday": "\u0431\u0435\u0439\u0441\u0435\u043d\u0431\u0456", + "Friday": "\u0436\u04b1\u043c\u0430", + "Saturday": "\u0441\u0435\u043d\u0431\u0456", + "Days": "\u041a\u04af\u043d\u0434\u0435\u0440", + "SortByValue": "\u0421\u04b1\u0440\u044b\u043f\u0442\u0430\u0443 \u0442\u04d9\u0441\u0456\u043b\u0456 {0}", + "LabelSortBy": "\u0421\u04b1\u0440\u044b\u043f\u0442\u0430\u0443 \u0442\u04d9\u0441\u0456\u043b\u0456:", + "LabelSortOrder": "\u0421\u04b1\u0440\u044b\u043f\u0442\u0430\u0443 \u0440\u0435\u0442\u0456:", + "HeaderPhotoAlbums": "\u0424\u043e\u0442\u043e\u0430\u043b\u044c\u0431\u043e\u043c\u0434\u0430\u0440", + "Photos": "\u0424\u043e\u0442\u043e\u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440", + "HeaderAppearsOn": "\u041a\u04e9\u0440\u0443\u0433\u0435 \u0431\u043e\u043b\u0430\u0434\u044b", + "List": "\u0422\u0456\u0437\u0456\u043c", + "RecordSeries": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f\u043d\u044b \u0436\u0430\u0437\u0443", + "HeaderCinemaMode": "\u041a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440 \u0440\u0435\u0436\u0456\u043c\u0456", + "HeaderCloudSync": "\u0411\u04b1\u043b\u0442\u0442\u044b\u049b \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443", + "Downloads": "\u0416\u04af\u043a\u0442\u0435\u0443\u043b\u0435\u0440", + "HeaderMyDownloads": "\u041c\u0435\u043d\u0456\u04a3 \u0436\u04af\u043a\u0442\u0435\u0443\u043b\u0435\u0440\u0456\u043c", + "HeaderOfflineDownloads": "\u0414\u0435\u0440\u0431\u0435\u0441 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a", + "HeaderOfflineDownloadsDescription": "\u041e\u04a3\u0430\u0439 \u0434\u0435\u0440\u0431\u0435\u0441 \u049b\u043e\u043b\u0434\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043b\u0430\u0440\u044b\u04a3\u044b\u0437\u0493\u0430 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u04a3\u044b\u0437.", + "CloudSyncFeatureDescription": "\u0421\u0430\u049b\u0442\u044b\u049b \u043a\u04e9\u0448\u0456\u0440\u043c\u0435\u043d\u0456, \u043c\u04b1\u0440\u0430\u0493\u0430\u0442\u0442\u0430\u0443\u0434\u044b \u0436\u04d9\u043d\u0435 \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443\u0434\u0456 \u0436\u0435\u04a3\u0456\u043b\u0434\u0435\u0442\u0443 \u04af\u0448\u0456\u043d \u0442\u0430\u0441\u044b\u0493\u044b\u0448 \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0431\u04b1\u043b\u0442\u043f\u0435\u043d \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0456\u04a3\u0456\u0437.", + "LiveTvFeatureDescription": "Emby Server \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u0493\u0430\u043d \u04af\u0439\u043b\u0435\u0441\u0456\u043c\u0434\u0456 \u0422\u0414-\u0442\u044e\u043d\u0435\u0440 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0441\u044b \u0430\u0440\u049b\u044b\u043b\u044b \u043a\u0435\u0437 \u043a\u0435\u043b\u0433\u0435\u043d Emby-\u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u0493\u0430 \u0422\u0414-\u044d\u0444\u0438\u0440\u0434\u0456 \u0442\u0456\u043a\u0435\u043b\u0435\u0439 \u0436\u0456\u0431\u0435\u0440\u0443.", + "DvrFeatureDescription": "Emby DVR \u043a\u0435\u0441\u0442\u0435\u0441\u0456\u043d\u0435 \u0436\u0435\u043a\u0435 \u044d\u0444\u0438\u0440\u043b\u0456\u043a \u0436\u0430\u0437\u0431\u0430\u043b\u0430\u0440\u0434\u044b, \u0442\u043e\u043f\u0442\u0430\u043c\u0430 \u0436\u0430\u0437\u0431\u0430\u043b\u0430\u0440\u0434\u044b, \u0436\u04d9\u043d\u0435 \u043e\u043d\u0430\u043d \u0431\u0430\u0441\u049b\u0430\u043b\u0430\u0440\u0434\u044b \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437.", + "CinemaModeFeatureDescription": "\u041a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440 \u0440\u0435\u0436\u0456\u043c\u0456 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440\u0434\u0456 \u0436\u04d9\u043d\u0435 \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u043a\u04e9\u0440\u043d\u0435\u0443\u0434\u0456 \u0444\u0438\u043b\u044c\u043c \u0430\u043b\u0434\u044b\u043d\u0434\u0430 \u043e\u0439\u043d\u0430\u0442\u0443 \u043a\u0438\u043d\u043e\u0437\u0430\u043b \u04d9\u0441\u0435\u0440\u0456\u043d \u0436\u0435\u0442\u043a\u0456\u0437\u0435\u0434\u0456.", + "HeaderFreeApps": "\u0422\u0435\u0433\u0456\u043d Emby \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u043b\u0430\u0440\u044b", + "FreeAppsFeatureDescription": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u043b\u0430\u0440\u044b\u04a3\u044b\u0437 \u04af\u0448\u0456\u043d Emby-\u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u043b\u0430\u0440\u044b\u043d\u0430 \u0442\u0435\u0433\u0456\u043d \u049b\u0430\u0442\u044b\u043d\u0430\u04a3\u044b\u0437.", + "HeaderBecomeProjectSupporter": "Emby Premiere \u0430\u043b\u0443", + "MessageActiveSubscriptionRequiredSeriesRecordings": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f\u043b\u0430\u0440\u0434\u044b\u04a3 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0436\u0430\u0437\u0431\u0430\u0441\u044b\u043d \u0436\u0430\u0441\u0430\u0443 \u04af\u0448\u0456\u043d \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 Emby Premiere \u0436\u0430\u0437\u044b\u043b\u044b\u043c\u044b \u049b\u0430\u0436\u0435\u0442.", + "LabelEmailAddress": "\u042d-\u043f\u043e\u0448\u0442\u0430 \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439\u044b:", + "PromoConvertRecordingsToStreamingFormat": "Emby Premiere \u0430\u0440\u049b\u044b\u043b\u044b \u0442\u0430\u0441\u044b\u043c\u0430\u043b\u0434\u0430\u0443\u0493\u0430 \u043e\u04a3\u0430\u0439 \u043f\u0456\u0448\u0456\u043d\u0434\u0435 \u0436\u0430\u0437\u0431\u0430\u043b\u0430\u0440\u0434\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443. \u0416\u0430\u0437\u0431\u0430\u043b\u0430\u0440 Emby Server \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456 \u043d\u0435\u0433\u0456\u0437\u0456\u043d\u0434\u0435, \u043d\u0430\u049b\u0442\u044b \u0443\u0430\u049b\u044b\u0442\u0442\u0430 MP4 \u043d\u0435\u043c\u0435\u0441\u0435 MKV \u043f\u0456\u0448\u0456\u043c\u0456\u043d\u0435 \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0456\u043b\u0435\u0434\u0456.", + "FeatureRequiresEmbyPremiere": "\u041e\u0441\u044b \u049b\u04b1\u0440\u0430\u043c\u0434\u0430\u0441 \u04af\u0448\u0456\u043d \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 Emby Premiere \u0436\u0430\u0437\u044b\u043b\u044b\u043c\u044b \u049b\u0430\u0436\u0435\u0442", + "HeaderConvertYourRecordings": "\u0416\u0430\u0437\u0431\u0430\u043b\u0430\u0440\u044b\u04a3\u044b\u0437\u0434\u044b \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443", + "Record": "\u0416\u0430\u0437\u0443", + "Save": "\u0421\u0430\u049b\u0442\u0430\u0443", + "Edit": "\u04e8\u04a3\u0434\u0435\u0443", + "Download": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443", + "Downloaded": "\u0416\u04af\u043a\u0442\u0435\u043b\u0456\u043f \u0430\u043b\u044b\u043d\u0434\u044b", + "Downloading": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443\u0434\u0430", + "Advanced": "\u041a\u0435\u04a3\u0435\u0439\u0442\u0456\u043b\u0433\u0435\u043d", + "Delete": "\u0416\u043e\u044e", + "HeaderDeleteItem": "\u0422\u0430\u0440\u043c\u0430\u049b\u0442\u044b \u0436\u043e\u044e", + "ConfirmDeleteItem": "\u041e\u0441\u044b \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u044b \u0436\u043e\u0439\u0493\u0430\u043d\u0434\u0430, \u043e\u043b \u0444\u0430\u0439\u043b \u0436\u04af\u0439\u0435\u0441\u0456\u043d\u0435\u043d \u0434\u0435, \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u04a3\u044b\u0437\u0434\u0430\u043d \u0434\u0430 \u0436\u043e\u0439\u044b\u043b\u0430\u0434\u044b. \u0428\u044b\u043d\u044b\u043c\u0435\u043d \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?", + "Refresh": "\u0416\u0430\u04a3\u0493\u044b\u0440\u0442\u0443", + "RefreshQueued": "\u0416\u0430\u04a3\u0493\u044b\u0440\u0442\u0443 \u043a\u0435\u0437\u0435\u043a\u0442\u0435.", + "AddToCollection": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b\u049b\u0430 \u04af\u0441\u0442\u0435\u0443", + "HeaderAddToCollection": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b\u049b\u0430 \u04af\u0441\u0442\u0435\u0443", + "NewCollection": "\u0416\u0430\u04a3\u0430 \u0436\u0438\u044b\u043d\u0442\u044b\u049b", + "LabelCollection": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b:", + "Help": "\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u0433\u0456 \u0430\u043d\u044b\u049b\u0442\u0430\u043c\u0430\u0493\u0430", + "LabelDisplayMode": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u0443 \u0440\u0435\u0436\u0456\u043c\u0456:", + "Desktop": "\u0416\u04b1\u043c\u044b\u0441 \u04af\u0441\u0442\u0435\u043b\u0456", + "Mobile": "\u04b0\u044f\u043b\u044b \/ \u041f\u043b\u0430\u043d\u0448\u0435\u0442\u0442\u0456\u043a", + "TV": "\u0422\u0414", + "DisplayModeHelp": "Emby \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0434\u0430 \u044d\u043a\u0440\u0430\u043d \u0442\u04af\u0440\u0456\u043d \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437.", + "LabelDisplayLanguage": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u0443 \u0442\u0456\u043b\u0456:", + "LabelDisplayLanguageHelp": "Emby \u0442\u04d9\u0440\u0436\u0456\u043c\u0435\u043b\u0435\u0443\u0456 \u0430\u0493\u044b\u043c\u0434\u0430\u0493\u044b \u0436\u043e\u0431\u0430 \u0431\u043e\u043b\u044b\u043f \u0442\u0430\u0431\u044b\u043b\u0430\u0434\u044b.", + "LearnHowYouCanContribute": "\u049a\u0430\u043b\u0430\u0439 \u04af\u043b\u0435\u0441 \u049b\u043e\u0441\u0443\u044b\u043d\u044b\u04a3\u044b\u0437 \u043c\u04af\u043c\u043a\u0456\u043d \u0442\u0443\u0440\u0430\u043b\u044b \u04af\u0439\u0440\u0435\u043d\u0456\u04a3\u0456\u0437.", + "NewCollectionHelp": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b\u0442\u0430\u0440 \u0441\u0456\u0437\u0433\u0435 \u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440\u0434\u0456\u04a3 \u0436\u04d9\u043d\u0435 \u0442\u0430\u0493\u044b \u0431\u0430\u0441\u049b\u0430 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u043d\u044b\u04a3 \u043c\u0430\u0437\u043c\u04b1\u043d\u044b\u043d \u0434\u0435\u0440\u0431\u0435\u0441\u0442\u0435\u043d\u0434\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0442\u043e\u043f\u0442\u0430\u0443\u043b\u0430\u0440\u044b\u043c\u0435\u043d \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0435\u0434\u0456.", + "SearchForCollectionInternetMetadata": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u043c\u0435\u043b\u0435\u0440 \u0431\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d \u0456\u0437\u0434\u0435\u0443", + "DisplayMissingEpisodesWithinSeasons": "\u0416\u043e\u049b \u0431\u04e9\u043b\u0456\u043c\u0434\u0435\u0440\u0434\u0456 \u043c\u0430\u0443\u0441\u044b\u043c \u0456\u0448\u0456\u043d\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443", + "DisplayMissingEpisodesWithinSeasonsHelp": "\u0411\u04b1\u043b \u0441\u043e\u043d\u0434\u0430\u0439-\u0430\u049b Emby Server \u043e\u0440\u043d\u0430\u0442\u0443\u044b\u043d\u0434\u0430\u0493\u044b \u0422\u0414 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u043b\u0430\u0440\u044b \u04af\u0448\u0456\u043d \u049b\u043e\u0441\u0443\u043b\u044b \u0431\u043e\u043b\u0443\u044b \u043a\u0435\u0440\u0435\u043a.", + "EnableThemeSongs": "\u0422\u0430\u049b\u044b\u0440\u044b\u043f\u0442\u044b\u049b \u04d9\u0443\u0435\u043d\u0434\u0435\u0440\u0434\u0456 \u049b\u043e\u0441\u0443", + "EnableBackdrops": "\u0410\u0440\u0442\u049b\u044b \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0434\u0456 \u049b\u043e\u0441\u0443", + "EnableThemeSongsHelp": "\u049a\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0434\u0430, \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u043d\u044b \u0448\u043e\u043b\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u0442\u0430\u049b\u044b\u0440\u044b\u043f\u0442\u044b\u049b \u04d9\u0443\u0435\u043d\u0434\u0435\u0440 \u04e9\u04a3\u0434\u0435 \u043e\u0439\u043d\u0430\u0442\u044b\u043b\u0430\u0434\u044b.", + "EnableBackdropsHelp": "\u049a\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0434\u0430, \u0430\u0440\u0442\u049b\u044b \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u043d\u044b \u0448\u043e\u043b\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u043a\u0435\u0439\u0431\u0456\u0440 \u0431\u0435\u0442\u0442\u0435\u0440\u0434\u0435 \u04e9\u04a3\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0435\u0434\u0456.", + "EnableThemeVideos": "\u0422\u0430\u049b\u044b\u0440\u044b\u043f\u0442\u044b\u049b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0434\u0456 \u049b\u043e\u0441\u0443", + "EnableThemeVideosHelp": "\u049a\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0434\u0430, \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u043d\u044b \u0448\u043e\u043b\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u0442\u0430\u049b\u044b\u0440\u044b\u043f\u0442\u044b\u049b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u04e9\u04a3\u0434\u0435 \u043e\u0439\u043d\u0430\u0442\u044b\u043b\u0430\u0434\u044b.", + "RunAtStartup": "\u0406\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0443\u0434\u0430\u043d \u0431\u0430\u0441\u0442\u0430\u043f \u043e\u0440\u044b\u043d\u0434\u0430\u0443", + "LabelScreensaver": "\u042d\u043a\u0440\u0430\u043d \u049b\u043e\u0440\u0493\u0430\u0443\u044b\u0448:", + "LabelSoundEffects": "\u0414\u044b\u0431\u044b\u0441\u0442\u044b\u049b \u04d9\u0441\u0435\u0440\u043b\u0435\u0440\u0456:", + "LabelSkin": "\u041c\u04b1\u049b\u0430\u0431\u0430:", + "LabelName": "\u0410\u0442\u044b:", + "NewCollectionNameExample": "\u041c\u044b\u0441\u0430\u043b: \u0416\u04b1\u043b\u0434\u044b\u0437 \u0441\u043e\u0493\u044b\u0441\u0442\u0430\u0440\u044b (\u0436\u0438\u044b\u043d\u0442\u044b\u049b)", + "MessageItemsAdded": "\u0422\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440 \u04af\u0441\u0442\u0435\u043b\u0433\u0435\u043d.", + "OptionNew": "\u0416\u0430\u04a3\u0430...", + "LabelPlaylist": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0456:", + "AddToPlaylist": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0456\u043d\u0435 \u04af\u0441\u0442\u0435\u0443", + "HeaderAddToPlaylist": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0456\u043d\u0435 \u04af\u0441\u0442\u0435\u0443", + "Subtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440", + "LabelTheme": "\u0422\u0430\u049b\u044b\u0440\u044b\u043f:", + "LabelDashboardTheme": "\u0421\u0435\u0440\u0432\u0435\u0440 \u0442\u0430\u049b\u0442\u0430\u0441\u044b\u043d\u044b\u04a3 \u0442\u0430\u049b\u044b\u0440\u044b\u0431\u044b:", + "SearchForSubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0434\u0456 \u0456\u0437\u0434\u0435\u0443", + "LabelLanguage": "\u0422\u0456\u043b:", + "Search": "\u0406\u0437\u0434\u0435\u0443", + "NoSubtitleSearchResultsFound": "\u0415\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u043d\u04d9\u0442\u0438\u0436\u0435\u043b\u0435\u0440 \u0442\u0430\u0431\u044b\u043b\u043c\u0430\u0434\u044b.", + "File": "\u0424\u0430\u0439\u043b", + "MessageAreYouSureDeleteSubtitles": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0444\u0430\u0439\u043b\u044b\u043d \u0436\u043e\u044e \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?", + "ConfirmDeletion": "\u0416\u043e\u044e\u0434\u044b \u0440\u0430\u0441\u0442\u0430\u0443", + "MySubtitles": "\u041c\u0435\u043d\u0456\u04a3 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0456\u043c", + "MessageDownloadQueued": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443 \u043a\u0435\u0437\u0435\u043a\u0442\u0435.", + "EditSubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0434\u0456 \u04e9\u04a3\u0434\u0435\u0443", + "UnlockGuide": "\u0422\u0435\u043b\u0435\u0433\u0438\u0434\u0442\u0456 \u049b\u04b1\u0440\u0441\u0430\u0443\u0434\u0430\u043d \u0431\u043e\u0441\u0430\u0442\u0443", + "RefreshMetadata": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0436\u0430\u04a3\u0493\u044b\u0440\u0442\u0443", + "ReplaceExistingImages": "\u0411\u0430\u0440 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0434\u0456 \u0430\u0443\u044b\u0441\u0442\u044b\u0440\u0443", + "ReplaceAllMetadata": "\u0411\u0430\u0440\u043b\u044b\u049b \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0430\u0443\u044b\u0441\u0442\u044b\u0440\u0443", + "SearchForMissingMetadata": "\u0416\u043e\u049b \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0456\u0437\u0434\u0435\u0443", + "LabelRefreshMode": "\u0416\u0430\u04a3\u0493\u044b\u0440\u0442\u0443 \u0440\u0435\u0436\u0456\u043c\u0456:", + "NoItemsFound": "\u0415\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440 \u0442\u0430\u0431\u044b\u043b\u043c\u0430\u0434\u044b.", + "HeaderSaySomethingLike": "\u041e\u0441\u044b\u043d\u0434\u0430\u0439 \u0441\u0438\u044f\u049b\u0442\u044b\u043d\u044b \u0430\u0439\u0442\u044b\u04a3\u044b\u0437...", + "ButtonTryAgain": "\u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u0443", + "HeaderYouSaid": "\u0421\u0456\u0437 \u0430\u0439\u0442\u049b\u0430\u043d\u044b\u04a3\u044b\u0437...", + "MessageWeDidntRecognizeCommand": "\u041e\u0441\u044b\u043d\u0434\u0430\u0439 \u043f\u04d9\u0440\u043c\u0435\u043d\u0434\u0456 \u0442\u0430\u043d\u044b\u043f \u0430\u0439\u044b\u0440\u043c\u0430\u0434\u044b\u049b.", + "MessageIfYouBlockedVoice": "\u0415\u0433\u0435\u0440 \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u0493\u0430 \u0434\u0430\u0443\u044b\u0441\u0442\u044b\u049b \u049b\u0430\u0442\u044b\u043d\u0430\u0443\u0434\u0430\u043d \u0431\u0430\u0441 \u0442\u0430\u0440\u0442\u0441\u0430\u04a3\u044b\u0437, \u049b\u0430\u0439\u0442\u0430 \u04d9\u0440\u0435\u043a\u0435\u0442\u0442\u0435\u043d\u0443\u0456\u04a3\u0456\u0437\u0434\u0435\u043d \u0430\u043b\u0434\u044b\u043d\u0430\u043d \u049b\u0430\u0439\u0442\u0430 \u0442\u0435\u04a3\u0448\u0435\u0443\u0456\u04a3\u0456\u0437 \u049b\u0430\u0436\u0435\u0442 \u0431\u043e\u043b\u0430\u0434\u044b.", + "ValueDiscNumber": "{0}-\u0434\u0438\u0441\u043a\u0456", + "Unrated": "\u0411\u0430\u0493\u0430\u043b\u0430\u043d\u0431\u0430\u0493\u0430\u043d", + "Favorite": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b", + "Like": "\u04b0\u043d\u0430\u0439\u0434\u044b", + "Dislike": "\u04b0\u043d\u0430\u043c\u0430\u0439\u0434\u044b", + "RefreshDialogHelp": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440 \u043c\u0435\u043d Emby Server \u0442\u0430\u049b\u0442\u0430\u0441\u044b\u043d\u0434\u0430 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u049b\u044b\u0437\u043c\u0435\u0442\u0442\u0435\u0440\u0456 \u043d\u0435\u0433\u0456\u0437\u0456\u043d\u0434\u0435 \u0436\u0430\u04a3\u0493\u044b\u0440\u0442\u044b\u043b\u0430\u0434\u044b.", + "Open": "\u0410\u0448\u0443", + "Play": "\u041e\u0439\u043d\u0430\u0442\u0443", + "AddToPlayQueue": "\u041e\u0439\u043d\u0430\u0442\u0443 \u043a\u0435\u0437\u0435\u0433\u0456\u043d\u0435 \u04af\u0441\u0442\u0435\u0443", + "Shuffle": "\u0410\u0440\u0430\u043b\u0430\u0441\u0442\u044b\u0440\u0443", + "Identify": "\u0410\u043d\u044b\u049b\u0442\u0430\u0443", + "EditImages": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0434\u0456 \u04e9\u04a3\u0434\u0435\u0443", + "EditMetadata": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u04e9\u04a3\u0434\u0435\u0443", + "Convert": "\u0422\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443", + "Sync": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443", + "InstantMix": "\u041b\u0435\u0437\u0434\u0456\u043a \u049b\u043e\u0441\u043f\u0430\u043b\u0430\u0443", + "ViewAlbum": "\u0410\u043b\u044c\u0431\u043e\u043c\u0434\u044b \u049b\u0430\u0440\u0430\u0443", + "ViewArtist": "\u041e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b\u043d\u044b \u049b\u0430\u0440\u0430\u0443", + "QueueAllFromHere": "\u0411\u04b1\u043b \u0430\u0440\u0430\u0434\u0430\u043d \u0431\u04d9\u0440\u0456\u043d \u043a\u0435\u0437\u0435\u043a\u043a\u0435", + "PlayAllFromHere": "\u0411\u04b1\u043b \u0430\u0440\u0430\u0434\u0430\u043d \u0431\u04d9\u0440\u0456\u043d \u043e\u0439\u043d\u0430\u0442\u0443", + "PlayFromBeginning": "\u0411\u0430\u0441\u044b\u043d\u0430\u043d \u043e\u0439\u043d\u0430\u0442\u0443", + "ResumeAt": "{0} \u0431\u0430\u0441\u0442\u0430\u043f \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443", + "RemoveFromPlaylist": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0456\u043d\u0435\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443", + "RemoveFromCollection": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b\u0442\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443", + "Sort": "\u0421\u04b1\u0440\u044b\u043f\u0442\u0430\u0443", + "Trailer": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440", + "MarkPlayed": "\u041e\u0439\u043d\u0430\u0442\u044b\u043b\u0493\u0430\u043d \u0434\u0435\u043f \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u0443", + "MarkUnplayed": "\u041e\u0439\u043d\u0430\u0442\u044b\u043b\u043c\u0430\u0493\u0430\u043d \u0434\u0435\u043f \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u0443", + "GroupVersions": "\u041d\u04b1\u0441\u049b\u0430\u043b\u0430\u0440\u0434\u044b \u0442\u043e\u043f\u0442\u0430\u0441\u0442\u044b\u0440\u0443", + "PleaseSelectTwoItems": "\u0415\u04a3 \u043a\u0435\u043c\u0456\u043d\u0434\u0435 \u0435\u043a\u0456 \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u044b \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437.", + "TryMultiSelect": "\u04ae\u043d\u0434\u0435\u0441\u043a\u0435\u043d \u0431\u04e9\u043b\u0435\u043a\u0442\u0435\u0443\u0434\u0456 \u0441\u044b\u043d\u0430\u043f \u043a\u04e9\u0440\u0443", + "TryMultiSelectMessage": "\u0411\u0456\u0440\u043d\u0435\u0448\u0435 \u0442\u0430\u0441\u044b\u0493\u044b\u0448 \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0435\u0440\u0456\u043d \u04e9\u04a3\u0434\u0435\u0443 \u04af\u0448\u0456\u043d, \u043a\u0435\u0437 \u043a\u0435\u043b\u0433\u0435\u043d \u043f\u043e\u0441\u0442\u0435\u0440\u0434\u0456 \u0436\u0430\u0439 \u0493\u0430\u043d\u0430 \u0442\u0456\u043d\u0442\u0443\u0456\u0440 \u0431\u0430\u0442\u044b\u0440\u043c\u0430\u0493\u0430 \u0431\u0430\u0441\u044b\u043f \u0442\u04b1\u0440\u044b\u043f \u043d\u04b1\u049b\u044b\u04a3\u044b\u0437 \u0436\u04d9\u043d\u0435 \u0431\u0430\u0441\u049b\u0430\u0440\u0443\u044b\u043d \u049b\u0430\u043b\u0430\u0493\u0430\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0435\u0440\u0434\u0456 \u0431\u04e9\u043b\u0435\u043a\u0442\u0435\u04a3\u0456\u0437. \u0421\u044b\u043d\u0430\u043f \u043a\u04e9\u0440\u0456\u04a3\u0456\u0437!", + "HeaderConfirmRecordingCancellation": "\u0416\u0430\u0437\u0443 \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443\u044b\u043d \u0440\u0430\u0441\u0442\u0430\u0443", + "MessageConfirmRecordingCancellation": "\u0416\u0430\u0437\u0443\u0434\u044b \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?", + "Error": "\u049a\u0430\u0442\u0435", + "VoiceInput": "\u0414\u0430\u0443\u044b\u0441\u0442\u044b\u049b \u0435\u043d\u0433\u0456\u0437\u0443", + "LabelContentType": "\u041c\u0430\u0437\u043c\u04b1\u043d \u0442\u04af\u0440\u0456:", + "LabelPath": "\u0416\u043e\u043b\u044b:", + "Playlists": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u0440\u0456", + "LabelTitle": "\u0410\u0442\u0430\u0443\u044b:", + "LabelOriginalTitle": "\u0411\u0430\u0441\u0442\u0430\u043f\u049b\u044b \u0430\u0442\u0430\u0443\u044b:", + "LabelSortTitle": "\u0410\u0442\u0430\u0443 \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0441\u04b1\u0440\u044b\u043f\u0442\u0430\u0443", + "LabelDateAdded": "\u04ae\u0441\u0442\u0435\u043b\u0433\u0435\u043d \u043a\u04af\u043d\u0456", + "DateAdded": "\u04ae\u0441\u0442\u0435\u043b\u0433\u0435\u043d \u043a\u04af\u043d\u0456", + "DatePlayed": "\u041e\u0439\u043d\u0430\u0442\u044b\u043b\u0493\u0430\u043d \u043a\u04af\u043d\u0456", + "ConfigureDateAdded": "\u04ae\u0441\u0442\u0435\u043b\u0433\u0435\u043d \u043a\u04af\u043d\u0456 Emby Server \u0442\u0430\u049b\u0442\u0430\u0441\u044b\u043d\u0434\u0430\u0493\u044b \u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456\u043d\u0434\u0435 \u0430\u043d\u044b\u049b\u0442\u0430\u043b\u0430\u0434\u044b", + "LabelStatus": "\u041a\u04af\u0439:", + "LabelArtists": "\u041e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b\u043b\u0430\u0440:", + "LabelArtistsHelp": "\u0411\u0456\u0440\u043d\u0435\u0448\u0443\u0456\u043d (;) \u0430\u0440\u049b\u044b\u043b\u044b \u0431\u04e9\u043b\u0456\u04a3\u0456\u0437", + "HeaderAlbumArtists": "\u0410\u043b\u044c\u0431\u043e\u043c \u043e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b\u043b\u0430\u0440\u044b", + "LabelAlbumArtists": "\u0410\u043b\u044c\u0431\u043e\u043c \u043e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b\u043b\u0430\u0440\u044b:", + "LabelAlbum": "\u0410\u043b\u044c\u0431\u043e\u043c:", + "Artists": "\u041e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b\u043b\u0430\u0440", + "ImdbRating": "IMDb \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u044b", + "CommunityRating": "\u049a\u0430\u0443\u044b\u043c \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u044b", + "LabelCommunityRating": "\u049a\u0430\u0443\u044b\u043c \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u044b:", + "LabelCriticRating": "\u0421\u044b\u043d\u0448\u044b\u043b\u0430\u0440 \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u044b:", + "CriticRating": "\u0421\u044b\u043d\u0448\u044b\u043b\u0430\u0440 \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u044b", + "LabelWebsite": "\u0492\u0430\u043b\u0430\u043c\u0442\u043e\u0440 \u0441\u0430\u0439\u0442\u044b:", + "LabelTagline": "\u041d\u0435\u0433\u0456\u0437\u0433\u0456 \u0441\u04e9\u0439\u043b\u0435\u043c:", + "LabelOverview": "\u0416\u0430\u043b\u043f\u044b \u0448\u043e\u043b\u0443:", + "LabelShortOverview": "\u049a\u044b\u0441\u049b\u0430\u0448\u0430 \u0448\u043e\u043b\u0443:", + "LabelReleaseDate": "\u0428\u044b\u0493\u0430\u0440\u0443 \u043a\u04af\u043d\u0456:", + "LabelYear": "\u0416\u044b\u043b:", + "LabelPlaceOfBirth": "\u0422\u0443\u0493\u0430\u043d \u0436\u0435\u0440\u0456:", + "Aired": "\u042d\u0444\u0438\u0440\u043b\u0456\u043a", + "LabelAirDays": "\u042d\u0444\u0438\u0440 \u043a\u04af\u043d\u0434\u0435\u0440\u0456:", + "LabelAirTime": "\u042d\u0444\u0438\u0440 \u0443\u0430\u049b\u044b\u0442\u044b:", + "LabelRuntimeMinutes": "\u04b0\u0437\u0430\u049b\u0442\u044b\u0493\u044b, \u043c\u0438\u043d:", + "LabelParentalRating": "\u0416\u0430\u0441\u0442\u0430\u0441 \u0441\u0430\u043d\u0430\u0442\u044b:", + "LabelCustomRating": "\u0422\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0441\u0430\u043d\u0430\u0442:", + "LabelOriginalAspectRatio": "\u0411\u0430\u0441\u0442\u0430\u043f\u049b\u044b \u043f\u0456\u0448\u0456\u043c\u0434\u0456\u043a \u0430\u0440\u0430\u049b\u0430\u0442\u044b\u043d\u0430\u0441\u044b:", + "Label3DFormat": "3D \u043f\u0456\u0448\u0456\u043c\u0456:", + "FormatValue": "\u041f\u0456\u0448\u0456\u043c: {0}", + "DownloadsValue": "{0} \u0436\u04af\u043a\u0442\u0435\u0443", + "PerfectMatch": "\u04ae\u0437\u0434\u0456\u043a \u0442\u0435\u04a3", + "EnableExternalVideoPlayers": "\u0421\u044b\u0440\u0442\u049b\u044b \u043e\u0439\u043d\u0430\u0442\u049b\u044b\u0448\u0442\u0430\u0440\u0434\u044b \u049b\u043e\u0441\u0443", + "EnableExternalVideoPlayersHelp": "\u0421\u044b\u0440\u0442\u049b\u044b \u043e\u0439\u043d\u0430\u0442\u049b\u044b\u0448 \u043c\u04d9\u0437\u0456\u0440\u0456 \u0431\u0435\u0439\u043d\u0435 \u043e\u0439\u043d\u0430\u0442\u0443\u0434\u044b \u0431\u0430\u0441\u0442\u0430\u0493\u0430\u043d \u043a\u0435\u0437\u0434\u0435 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u0435\u0434\u0456.", + "HeaderSpecialEpisodeInfo": "\u0410\u0440\u043d\u0430\u0439\u044b \u0431\u04e9\u043b\u0456\u043c \u0442\u0443\u0440\u0430\u043b\u044b", + "LabelAirsBeforeSeason": "\"Airs before\" \u043c\u0430\u0443\u0441\u044b\u043c\u044b", + "LabelAirsAfterSeason": "\"Airs after\" \u043c\u0430\u0443\u0441\u044b\u043c\u044b", + "LabelAirsBeforeEpisode": "\"Airs after\" \u0431\u04e9\u043b\u0456\u043c\u0456", + "HeaderExternalIds": "\u0421\u044b\u0440\u0442\u049b\u044b \u0441\u04d9\u0439\u043a\u0435\u0441\u0442\u0435\u043d\u0434\u0456\u0440\u0433\u0456\u0448\u0442\u0435\u0440:", + "HeaderDisplaySettings": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456", + "LabelDisplayOrder": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u0443 \u0440\u0435\u0442\u0456:", + "Display": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u0443", + "Countries": "\u0415\u043b\u0434\u0435\u0440", + "Genres": "\u0416\u0430\u043d\u0440\u043b\u0430\u0440", + "Studios": "\u0421\u0442\u0443\u0434\u0438\u044f\u043b\u0430\u0440", + "Tags": "\u0422\u0435\u0433\u0442\u0435\u0440", + "HeaderMetadataSettings": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456", + "People": "\u0410\u0434\u0430\u043c\u0434\u0430\u0440", + "LabelMetadataDownloadLanguage": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443 \u0442\u0456\u043b\u0456\u043d\u0456\u04a3 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456:", + "LabelLockItemToPreventChanges": "\u041e\u0441\u044b \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u044b \u043a\u0435\u043b\u0435\u0448\u0435\u043a \u04e9\u0437\u0433\u0435\u0440\u0442\u0443\u043b\u0435\u0440\u0434\u0435\u043d \u049b\u04b1\u0440\u0441\u0430\u0443\u043b\u0430\u0443", + "MessageLeaveEmptyToInherit": "\u0422\u0435\u043a\u0442\u0456\u043a \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u043d, \u043d\u0435\u043c\u0435\u0441\u0435 \u0493\u0430\u043b\u0430\u043c\u0434\u044b\u049b \u04d9\u0434\u0435\u043f\u043a\u0456 \u043c\u04d9\u043d\u0456\u043d\u0435\u043d\u0456. \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440 \u043c\u04b1\u0440\u0430\u0441\u044b\u043d\u0430 \u0438\u0435\u043b\u0435\u043d\u0443 \u04af\u0448\u0456\u043d \u0431\u043e\u0441 \u049b\u0430\u043b\u0434\u044b\u0440\u044b\u04a3\u044b\u0437.", + "LabelCountry": "\u0415\u043b:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "\u0422\u0443\u0493\u0430\u043d \u0436\u044b\u043b\u044b:", + "LabelBirthDate": "\u0422\u0443\u0493\u0430\u043d \u043a\u04af\u043d\u0456:", + "LabelDeathDate": "\u04e8\u043b\u0433\u0435\u043d \u043a\u04af\u043d\u0456:", + "LabelEndDate": "\u0410\u044f\u049b\u0442\u0430\u043b\u0443 \u043a\u04af\u043d\u0456:", + "LabelSeasonNumber": "\u041c\u0430\u0443\u0441\u044b\u043c \u043d\u04e9\u043c\u0456\u0440\u0456:", + "LabelEpisodeNumber": "\u0411\u04e9\u043b\u0456\u043c \u043d\u04e9\u043c\u0456\u0440\u0456:", + "LabelTrackNumber": "\u0416\u043e\u043b\u0448\u044b\u049b \u043d\u04e9\u043c\u0456\u0440\u0456:", + "LabelNumber": "\u041d\u04e9\u043c\u0456\u0440\u0456:", + "LabelDiscNumber": "\u0414\u0438\u0441\u043a\u0456 \u043d\u04e9\u043c\u0456\u0440\u0456:", + "LabelParentNumber": "\u0422\u0435\u043a\u0442\u0456\u043a \u043d\u04e9\u043c\u0456\u0440:", + "SortName": "\u0421\u04b1\u0440\u044b\u043f\u0442\u0430\u043b\u0430\u0442\u044b\u043d \u0430\u0442\u044b", + "ReleaseDate": "\u0428\u044b\u0493\u0430\u0440\u0443 \u043a\u0435\u0437\u0456", + "Continuing": "\u0416\u0430\u043b\u0493\u0430\u0441\u0443\u0434\u0430", + "Ended": "\u0410\u044f\u049b\u0442\u0430\u043b\u0434\u044b", + "HeaderEnabledFields": "\u049a\u043e\u0441\u044b\u043b\u0493\u0430\u043d \u04e9\u0440\u0456\u0441\u0442\u0435\u0440", + "HeaderEnabledFieldsHelp": "\u049a\u04b1\u0440\u0441\u0430\u0443\u043b\u0430\u0443 \u04af\u0448\u0456\u043d \u0436\u04d9\u043d\u0435 \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u04e9\u0437\u0433\u0435\u0440\u0442\u0443\u0456\u043d\u0435 \u0442\u044b\u0439\u044b\u043c \u0441\u0430\u043b\u0443 \u04af\u0448\u0456\u043d, \u04e9\u0440\u0456\u0441\u0442\u0435\u043d \u049b\u04b1\u0441\u0431\u0435\u043b\u0433\u0456\u043d\u0456 \u0430\u043b\u044b\u04a3\u044b\u0437.", + "Backdrops": "\u0410\u0440\u0442\u049b\u044b \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440", + "Images": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u0440", + "Runtime": "\u04b0\u0437\u0430\u049b\u0442\u044b\u0493\u044b", + "ProductionLocations": "\u04e8\u043d\u0434\u0456\u0440\u0443 \u043e\u0440\u044b\u043d\u0434\u0430\u0440\u044b", + "BirthLocation": "\u0422\u0443\u0493\u0430\u043d \u043e\u0440\u043d\u044b", + "ParentalRating": "\u0416\u0430\u0441\u0442\u0430\u0441 \u0441\u0430\u043d\u0430\u0442\u044b", + "PlayCount": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0435\u0441\u0435\u0431\u0456", + "Name": "\u0410\u0442\u044b", + "Overview": "\u0416\u0430\u043b\u043f\u044b \u0448\u043e\u043b\u0443", + "LabelType": "\u0422\u04af\u0440\u0456:", + "LabelPersonRole": "\u0420\u04e9\u043b\u0456:", + "LabelPersonRoleHelp": "\u041c\u044b\u0441\u0430\u043b: \u0411\u0430\u043b\u043c\u04b1\u0437\u0434\u0430\u049b \u0444\u0443\u0440\u0433\u043e\u043d\u044b\u043d\u044b\u04a3 \u0436\u04af\u0440\u0433\u0456\u0437\u0443\u0448\u0456\u0441\u0456", + "Actor": "\u0410\u043a\u0442\u0435\u0440", + "Composer": "\u041a\u043e\u043c\u043f\u043e\u0437\u0438\u0442\u043e\u0440", + "Director": "\u0420\u0435\u0436\u0438\u0441\u0441\u0435\u0440", + "GuestStar": "\u0428\u0430\u049b\u044b\u0440\u044b\u043b\u0493\u0430\u043d \u0430\u043a\u0442\u0435\u0440", + "Producer": "\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440", + "Writer": "\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439\u0448\u0456", + "MessageNoSyncJobsFound": "\u0416\u04af\u043a\u0442\u0435\u0443\u043b\u0435\u0440 \u0442\u0430\u0431\u044b\u043b\u043c\u0430\u0434\u044b. \u0411\u04af\u043a\u0456\u043b \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u0434\u0430\u0493\u044b \u0416\u04af\u043a\u0442\u0435\u0443 \u0442\u04af\u0439\u043c\u0435\u0448\u0456\u043a\u0442\u0435\u0440\u0456\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u043f \u0436\u04af\u043a\u0442\u0435\u0443\u0443 \u0436\u04b1\u043c\u044b\u0441\u0442\u0430\u0440\u044b\u043d \u0436\u0430\u0441\u0430\u04a3\u044b\u0437.", + "MessageNoDownloadsFound": "\u0414\u0435\u0440\u0431\u0435\u0441 \u0436\u04af\u043a\u0442\u0435\u0443\u043b\u0435\u0440 \u0436\u043e\u049b. \u0411\u04af\u043a\u0456\u043b \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u0434\u0430\u0493\u044b \u0416\u04af\u043a\u0442\u0435\u0443 \u0442\u04af\u0439\u043c\u0435\u0448\u0456\u0433\u0456\u043d \u0431\u0430\u0441\u044b\u043f \u0434\u0435\u0440\u0431\u0435\u0441 \u049b\u043e\u043b\u0434\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u04a3\u044b\u0437.", + "InstallingPackage": "{0} \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u0443\u0434\u0430", + "PackageInstallCompleted": "{0} \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u0443\u044b \u0430\u044f\u049b\u0442\u0430\u043b\u0434\u044b.", + "PackageInstallFailed": "{0} \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u0443\u044b \u0441\u04d9\u0442\u0441\u0456\u0437.", + "PackageInstallCancelled": "{0} \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u0443\u044b \u0431\u043e\u043b\u0434\u044b\u0440\u044b\u043b\u043c\u0430\u0434\u044b.", + "SeriesYearToPresent": "{0} - \u049b\u0430\u0437\u0456\u0440\u0434\u0435", + "ValueOneItem": "1 \u0442\u0430\u0440\u043c\u0430\u049b", + "ValueOneSong": "1 \u04d9\u0443\u0435\u043d", + "ValueSongCount": "{0} \u04d9\u0443\u0435\u043d", + "ValueOneMovie": "1 \u0444\u0438\u043b\u044c\u043c", + "ValueMovieCount": "{0} \u0444\u0438\u043b\u044c\u043c", + "ValueOneSeries": "1 \u0442\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f", + "ValueSeriesCount": "{0} \u0442\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f", + "ValueOneEpisode": "1 \u0431\u04e9\u043b\u0456\u043c", + "ValueEpisodeCount": "{0} \u0431\u04e9\u043b\u0456\u043c", + "ValueOneGame": "1 \u043e\u0439\u044b\u043d", + "ValueGameCount": "{0} \u043e\u0439\u044b\u043d", + "ValueOneAlbum": "1 \u0430\u043b\u044c\u0431\u043e\u043c", + "ValueAlbumCount": "{0} \u0430\u043b\u044c\u0431\u043e\u043c", + "ValueOneMusicVideo": "1 \u043c\u0443\u0437\u044b\u043a\u0430\u043b\u044b\u049b \u0431\u0435\u0439\u043d\u0435", + "ValueMusicVideoCount": "{0} \u043c\u0443\u0437\u044b\u043a\u0430\u043b\u044b\u049b \u0431\u0435\u0439\u043d\u0435", + "ValueMinutes": "{0} \u043c\u0438\u043d", + "Albums": "\u0410\u043b\u044c\u0431\u043e\u043c\u0434\u0430\u0440", + "Songs": "\u04d8\u0443\u0435\u043d\u0434\u0435\u0440", + "Books": "\u041a\u0456\u0442\u0430\u043f\u0442\u0430\u0440", + "HeaderAudioBooks": "\u0414\u044b\u0431\u044b\u0441\u0442\u044b\u049b \u043a\u0456\u0442\u0430\u043f\u0442\u0430\u0440", + "HeaderIdentifyItemHelp": "\u0406\u0437\u0434\u0435\u0443\u0434\u0456\u04a3 \u0431\u0456\u0440 \u043d\u0435 \u0431\u0456\u0440\u043d\u0435\u0448\u0435 \u0448\u0430\u0440\u0442\u044b\u043d \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437. \u0406\u0437\u0434\u0435\u0443 \u043d\u04d9\u0442\u0438\u0436\u0435\u043b\u0435\u0440\u0456\u043d \u043a\u04e9\u0431\u0435\u0439\u0442\u0443 \u04af\u0448\u0456\u043d \u0448\u0430\u0440\u0442\u0442\u044b \u0430\u043b\u0430\u0441\u0442\u0430\u04a3\u044b\u0437.", + "PleaseEnterNameOrId": "\u0410\u0442\u044b\u043d \u043d\u0435\u043c\u0435\u0441\u0435 \u0441\u044b\u0440\u0442\u049b\u044b ID \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437.", + "MessageItemSaved": "\u0422\u0430\u0440\u043c\u0430\u049b \u0441\u0430\u049b\u0442\u0430\u043b\u0434\u044b.", + "SearchResults": "\u0406\u0437\u0434\u0435\u0443 \u043d\u04d9\u0442\u0438\u0436\u0435\u043b\u0435\u0440\u0456", + "ServerNameIsRestarting": "Emby Server - {0} \u049b\u0430\u0439\u0442\u0430 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0443\u0434\u0430.", + "ServerNameIsShuttingDown": "Emby Server - {0} \u0436\u04b1\u043c\u044b\u0441\u044b\u043d \u0430\u044f\u049b\u0442\u0430\u0443\u0434\u0430.", + "HeaderDeleteItems": "\u0422\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440\u0434\u044b \u0436\u043e\u044e", + "ConfirmDeleteItems": "\u041e\u0441\u044b \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440\u0434\u044b \u0436\u043e\u0439\u0493\u0430\u043d\u0434\u0430, \u043e\u043b\u0430\u0440 \u0444\u0430\u0439\u043b\u0434\u044b\u049b \u0436\u04af\u0439\u0435\u0441\u0456\u043d\u0435\u043d \u0434\u0435 \u0436\u04d9\u043d\u0435 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u04a3\u044b\u0437\u0434\u0430\u043d \u0434\u0430 \u0435\u043a\u0435\u0443\u0456\u043d\u0434\u0435 \u0436\u043e\u0439\u044b\u043b\u0430\u0434. \u0421\u0456\u0437 \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443 \u049b\u0430\u043b\u0430\u0439\u0441\u044b\u0437 \u0431\u0430? \u0428\u044b\u043d\u044b\u043c\u0435\u043d \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?", + "PleaseRestartServerName": "Emby Server \u04af\u0448\u0456\u043d \u049b\u0430\u0439\u0442\u0430 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u04a3\u044b\u0437 - {0}.", + "LabelSyncJobName": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u044b\u043d\u044b\u04a3 \u0430\u0442\u044b:", + "SyncingDots": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0440\u0456\u043b\u0443\u0434\u0435", + "ConvertingDots": "\u0422\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0456\u043b\u0443\u0434\u0435", + "LabelQuality": "\u0421\u0430\u043f\u0430\u0441\u044b:", + "LabelSyncNoTargetsHelp": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443\u0434\u044b \u049b\u043e\u043b\u0434\u0430\u0439\u0442\u044b\u043d \u049b\u0430\u0439\u0431\u0456\u0440 \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430 \u0430\u0493\u044b\u043c\u0434\u0430 \u0442\u0430\u0431\u044b\u043b\u043c\u0430\u043c\u0430\u0493\u0430\u043d \u0431\u043e\u043b\u044b\u043f \u043a\u04e9\u0440\u0456\u043d\u0435\u0434\u0456.", + "DownloadingDots": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443\u0434\u0430...", + "HeaderSyncRequiresSub": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443 \u04af\u0448\u0456\u043d \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 Emby Premiere \u0436\u0430\u0437\u044b\u043b\u044b\u043c\u044b \u049b\u0430\u0436\u0435\u0442", + "LearnMore": "\u041a\u04e9\u0431\u0456\u0440\u0435\u043a \u0431\u0456\u043b\u0443", + "LabelProfile": "\u041f\u0440\u043e\u0444\u0430\u0439\u043b:", + "LabelBitrateMbps": "\u049a\u0430\u0440\u049b\u044b\u043d\u044b (\u041c\u0431\u0438\u0442\/\u0441):", + "ConvertUnwatchedVideosOnly": "\u049a\u0430\u0440\u0430\u043b\u043c\u0430\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0434\u0456 \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443", + "SyncUnwatchedVideosOnly": "\u049a\u0430\u0440\u0430\u043b\u043c\u0430\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u0443", + "ConvertUnwatchedVideosOnlyHelp": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u049b\u0430\u0440\u0430\u043b\u043c\u0430\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u043b\u0435\u0434\u0456", + "SyncUnwatchedVideosOnlyHelp": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u049b\u0430\u0440\u0430\u043b\u043c\u0430\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u0436\u04af\u043a\u0442\u0435\u043b\u0435\u0434\u0456, \u049b\u0430\u0440\u0430\u043b\u0493\u0430\u043d\u043d\u0430\u043d \u043a\u0435\u0439\u0456\u043d \u049b\u04b1\u0440-\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0430\u0434\u044b.", + "AutomaticallySyncNewContent": "\u0416\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u0436\u04af\u043a\u0442\u0435\u0443", + "AutomaticallySyncNewContentHelp": "\u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430\u0493\u0430 \u0436\u0430\u04a3\u0430\u0434\u0430\u043d \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d \u043c\u0430\u0437\u043c\u04b1\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u043e\u0441\u044b \u049b\u04b1\u0440-\u0493\u044b\u0493\u0430 \u0436\u04af\u043a\u0442\u0435\u043b\u0435\u0434\u0456.", + "AutomaticallyConvertNewContent": "\u0416\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443", + "AutomaticallyConvertNewContentHelp": "\u041e\u0441\u044b \u049b\u0430\u043b\u044c\u0430\u0493\u0430 \u0436\u0430\u04a3\u0430\u0434\u0430\u043d \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d \u043c\u0430\u0437\u043c\u04b1\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u043e\u0441\u044b \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u043b\u0435\u0434\u0456.", + "LabelItemLimit": "\u0422\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440 \u0448\u0435\u0433\u0456:", + "ConvertItemLimitHelp": "\u041c\u0456\u043d\u0434\u0435\u0442\u0442\u0456 \u0435\u043c\u0435\u0441: \u0422\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u043b\u0435\u0442\u0456\u043d \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440 \u0441\u0430\u043d\u044b \u0448\u0435\u0433\u0456\u043d \u043e\u0440\u043d\u0430\u0442\u044b\u04a3\u044b\u0437.", + "DownloadItemLimitHelp": "\u041c\u0456\u043d\u0434\u0435\u0442\u0442\u0456 \u0435\u043c\u0435\u0441: \u0416\u04af\u043a\u0442\u0435\u043b\u0435\u0442\u0456\u043d \u0442\u0430\u0440\u043c\u0430\u049b \u0441\u0430\u043d\u044b\u043d\u044b\u04a3 \u0448\u0435\u0433\u0456\u043d \u043e\u0440\u043d\u0430\u0442\u044b\u04a3\u044b\u0437.", + "PleaseSelectDeviceToSyncTo": "\u049a\u0430\u0439\u0434\u0430 \u0436\u04af\u043a\u0442\u0435\u043b\u0435\u0442\u0456\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043d\u044b \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437.", + "Screenshots": "\u042d\u043a\u0440\u0430\u043d \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0456", + "MoveRight": "\u041e\u04a3\u0493\u0430 \u0436\u044b\u043b\u0436\u044b\u0442\u0443", + "MoveLeft": "\u0421\u043e\u043b\u0493\u0430 \u0436\u044b\u043b\u0436\u044b\u0442\u0443", + "ConfirmDeleteImage": "\u0421\u0443\u0440\u0435\u0442\u0442\u0456 \u0436\u043e\u044f\u043c\u044b\u0437 \u0431\u0430?", + "HeaderEditImages": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0434\u0456 \u04e9\u04a3\u0434\u0435\u0443", + "Settings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440", + "ShowIndicatorsFor": "\u041c\u044b\u043d\u0430\u0443 \u04af\u0448\u0456\u043d \u0431\u0435\u043b\u0433\u0456 \u043a\u04e9\u0440\u0441\u0435\u0442\u0443:", + "NewEpisodes": "\u0416\u0430\u04a3\u0430 \u0431\u04e9\u043b\u0456\u043c\u0434\u0435\u0440", + "Episodes": "\u0411\u04e9\u043b\u0456\u043c\u0434\u0435\u0440", + "HDPrograms": "HD-\u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c\u0434\u0435\u0440", + "Programs": "\u041a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c\u0434\u0435\u0440", + "LiveBroadcasts": "\u0422\u0456\u043a\u0435\u043b\u0435\u0439 \u0442\u0430\u0440\u0430\u0442\u044b\u043c\u0434\u0430\u0440", + "Premieres": "\u041f\u0440\u0435\u043c\u044c\u0435\u0440\u0430\u043b\u0430\u0440", + "RepeatEpisodes": "\u0411\u04e9\u043b\u0456\u043c\u0434\u0435\u0440\u0434\u0456\u04a3 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u043d\u0443\u044b", + "DvrSubscriptionRequired": "Emby DVR \u04af\u0448\u0456\u043d \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 Emby Premiere \u0436\u0430\u0437\u044b\u043b\u044b\u043c\u044b \u049b\u0430\u0436\u0435\u0442", + "HeaderCancelRecording": "\u0416\u0430\u0437\u0443\u0434\u044b \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443", + "CancelRecording": "\u0416\u0430\u0437\u0443\u0434\u044b \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443", + "HeaderKeepRecording": "\u0416\u0430\u0437\u0443\u0434\u044b \u0441\u0430\u049b\u0442\u0430\u043f \u049b\u0430\u043b\u0443", + "HeaderCancelSeries": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f\u043d\u044b \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443", + "HeaderKeepSeries": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f\u043d\u044b \u0441\u0430\u049b\u0442\u0430\u043f \u049b\u0430\u043b\u0443", + "HeaderLearnMore": "\u041a\u04e9\u0431\u0456\u0440\u0435\u043a \u0431\u0456\u043b\u0443", + "DeleteMedia": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0456 \u0436\u043e\u044e", + "SeriesSettings": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456", + "HeaderRecordingOptions": "\u0416\u0430\u0437\u0443 \u043e\u043f\u0446\u0438\u044f\u043b\u0430\u0440\u044b", + "CancelSeries": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f\u043d\u044b \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443", + "DoNotRecord": "\u0416\u0430\u0437\u0443\u0493\u0430 \u0431\u043e\u043b\u043c\u0430\u0439\u0434\u044b", + "HeaderSeriesOptions": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f \u043e\u043f\u0446\u0438\u044f\u043b\u0430\u0440\u044b", + "LabelChannels": "\u0410\u0440\u043d\u0430\u043b\u0430\u0440:", + "ChannelNameOnly": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 {0} \u0430\u0440\u043d\u0430\u0441\u044b", + "Anytime": "\u04d8\u0440\u043a\u0435\u0437\u0434\u0435", + "AnyLanguage": "\u049a\u0430\u0439-\u049b\u0430\u0439\u0441\u044b \u0442\u0456\u043b", + "AroundTime": "{0} \u0430\u0439\u043d\u0430\u043b\u0430\u0441\u044b\u043d\u0434\u0430", + "All": "\u0411\u04d9\u0440\u0456", + "AllChannels": "\u0411\u0430\u0440\u043b\u044b\u049b \u0430\u0440\u043d\u0430\u043b\u0430\u0440", + "LabelRecord": "\u0416\u0430\u0437\u0443:", + "NewEpisodesOnly": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u0436\u0430\u04a3\u0430 \u0431\u04e9\u043b\u0456\u043c\u0434\u0435\u0440\u0434\u0456", + "AllEpisodes": "\u0411\u0430\u0440\u043b\u044b\u049b \u0431\u04e9\u043b\u0456\u043c\u0434\u0435\u0440", + "LabelStartWhenPossible": "\u041c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u043a \u0431\u043e\u043b\u0493\u0430\u043d\u0434\u0430 \u0431\u0430\u0441\u0442\u0430\u0443:", + "LabelStopWhenPossible": "\u041c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u043a \u0431\u043e\u043b\u0493\u0430\u043d\u0434\u0430 \u0442\u043e\u049b\u0442\u0430\u0442\u0443:", + "MinutesBefore": "\u043c\u0438\u043d\u0443\u0442 \u0430\u043b\u0434\u044b\u043d\u0434\u0430", + "MinutesAfter": "\u043c\u0438\u043d\u0443\u0442 \u0441\u043e\u04a3\u044b\u04a3\u0434\u0430", + "SkipEpisodesAlreadyInMyLibrary": "\u041c\u0435\u043d\u0456\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u043c\u0434\u0430 \u0431\u0430\u0440 \u0431\u04e9\u043b\u0456\u043c\u0434\u0435\u0440\u0434\u0456 \u0436\u0430\u0437\u0431\u0430\u0443", + "SkipEpisodesAlreadyInMyLibraryHelp": "\u049a\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0493\u0430\u043d\u0434\u0430, \u0431\u04e9\u043b\u0456\u043c\u0434\u0435\u0440 \u043c\u0430\u0443\u0441\u044b\u043c \u0436\u04d9\u043d\u0435 \u0431\u04e9\u043b\u0456\u043c \u043d\u04e9\u043c\u0456\u0440\u043b\u0435\u0440\u0456 \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0441\u0430\u043b\u044b\u0441\u0442\u044b\u0440\u044b\u043b\u0430\u0434\u044b.", + "LabelKeepUpTo": "\u041e\u0441\u044b\u0493\u0430\u043d \u0434\u0435\u0439\u0456\u043d \u0441\u0430\u049b\u0442\u0430\u043f \u049b\u0430\u043b\u0443:", + "AsManyAsPossible": "\u041c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u0433\u0456\u043d\u0448\u0435 \u043a\u04e9\u043f", + "DefaultErrorMessage": "\u0421\u0430\u0443\u0430\u043b \u04e9\u04a3\u0434\u0435\u043b\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.", + "LabelKeep:": "\u0421\u0430\u049b\u0442\u0430\u043f \u049b\u0430\u043b\u0443:", + "UntilIDelete": "\u041c\u0435\u043d \u0436\u043e\u0439\u0493\u0430\u043d\u0448\u0430 \u0434\u0435\u0439\u0456\u043d", + "UntilSpaceNeeded": "\u041e\u0440\u044b\u043d \u043a\u0435\u0440\u0435\u043a \u0431\u043e\u043b\u0493\u0430\u043d\u0448\u0430 \u0434\u0435\u0439\u0456\u043d", + "Categories": "\u0421\u0430\u043d\u0430\u0442\u0442\u0430\u0440", + "Sports": "\u0421\u043f\u043e\u0440\u0442", + "News": "\u0416\u0430\u04a3\u0430\u043b\u044b\u049b", + "Movies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440", + "Kids": "\u0411\u0430\u043b\u0430\u043b\u044b\u049b", + "EnableColorCodedBackgrounds": "\u0422\u04af\u0441\u043f\u0435\u043d \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u043d\u0433\u0435\u043d \u04e9\u04a3\u0434\u0435\u0440\u0434\u0456 \u049b\u043e\u0441\u0443", + "SortChannelsBy": "\u0410\u0440\u043d\u0430\u043b\u0430\u0440\u0434\u044b \u0441\u04b1\u0440\u044b\u043f\u0442\u0430\u0443 \u0442\u04d9\u0441\u0456\u043b\u0456:", + "RecentlyWatched": "\u0416\u0443\u044b\u049b\u0442\u0430 \u049b\u0430\u0440\u0430\u043b\u0493\u0430\u043d", + "ChannelNumber": "\u0410\u0440\u043d\u0430 \u043d\u04e9\u043c\u0456\u0440\u0456", + "HeaderBenefitsEmbyPremiere": "Emby Premiere \u0430\u0440\u0442\u044b\u049b\u0448\u044b\u043b\u044b\u049b\u0442\u0430\u0440\u044b", + "ThankYouForTryingEnjoyOneMinute": "\u0411\u0456\u0440 \u043c\u0438\u043d\u04e9\u0442 \u043e\u0439\u043d\u0430\u0442\u0443\u0434\u044b \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u04a3\u044b\u0437. Emby \u0441\u044b\u043d\u0430\u043f \u043a\u04e9\u0440\u0433\u0435\u043d\u0456\u04a3\u0456\u0437\u0433\u0435 \u0440\u0430\u049b\u043c\u0435\u0442.", + "HeaderTryPlayback": "\u041e\u0439\u043d\u0430\u0442\u0443\u0434\u044b \u0441\u044b\u043d\u0430\u043f \u043a\u04e9\u0440\u0456\u04a3\u0456\u0437", + "HowDidYouPay": "\u049a\u0430\u043b\u0430\u0439 \u0442\u04e9\u043b\u0435\u0434\u0456\u04a3\u0456\u0437?", + "IHaveEmbyPremiere": "\u041c\u0435\u043d\u0434\u0435 Emby Premiere \u0431\u0430\u0440", + "IPurchasedThisApp": "\u041c\u0435\u043d \u043e\u0441\u044b \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u043d\u044b \u0441\u0430\u0442\u044b\u043f \u0430\u043b\u0434\u044b\u043c", + "ButtonRestorePreviousPurchase": "\u0421\u0430\u0442\u044b\u043f \u0430\u043b\u0493\u0430\u043d\u0434\u044b \u049b\u0430\u043b\u043f\u044b\u043d\u0430 \u043a\u0435\u043b\u0442\u0456\u0440\u0443", + "ButtonUnlockWithPurchase": "\u0421\u0430\u0442\u044b\u043f \u0430\u043b\u0443\u043c\u0435\u043d \u049b\u04b1\u0440\u0441\u0430\u0443\u0434\u0430\u043d \u0431\u043e\u0441\u0430\u0442\u0443", + "ButtonUnlockPrice": "{0} \u049b\u04b1\u043b\u044b\u043f\u0442\u0430\u043c\u0430\u0443", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere \u0430\u0439 \u0431\u043e\u0439\u044b\u043d\u0448\u0430 {0}", + "HeaderAlreadyPaid": "\u04d8\u043b\u0434\u0435\u049b\u0430\u0448\u0430\u043d \u0442\u04e9\u043b\u0435\u043d\u0434\u0456 \u043c\u0435?", + "ButtonPlayOneMinute": "\u0411\u0456\u0440 \u043c\u0438\u043d\u04e9\u0442 \u043e\u0439\u043d\u0430\u0442\u0443", + "PlaceFavoriteChannelsAtBeginning": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b \u0430\u0440\u043d\u0430\u043b\u0430\u0440\u0434\u044b \u0435\u04a3 \u0431\u0430\u0441\u044b\u043d\u0430\u043d \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0442\u044b\u0440\u0443", + "HeaderUnlockFeature": "\u0410\u0440\u0442\u044b\u049b\u0448\u044b\u043b\u044b\u049b \u049b\u04b1\u0440\u0441\u0430\u0443\u044b\u043d \u0431\u043e\u0441\u0430\u0442\u0443", + "MessageDidYouKnowCinemaMode": "Emby Premiere \u0430\u0440\u049b\u044b\u043b\u044b, \u041a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440 \u0440\u0435\u0436\u0456\u043c\u0456 \u0441\u0438\u044f\u049b\u0442\u044b \u049b\u04b1\u0440\u0430\u043c\u0434\u0430\u0441\u0442\u0430\u0440\u043c\u0435\u043d \u0442\u04d9\u0436\u0456\u0440\u0438\u0431\u0435\u04a3\u0456\u0437\u0434\u0456 \u0436\u0430\u049b\u0441\u0430\u0440\u0442\u0443\u044b\u04a3\u044b\u0437 \u043c\u04af\u043c\u043a\u0456\u043d \u0442\u0443\u0440\u0430\u043b\u044b \u0431\u0456\u043b\u0435\u0441\u0456\u0437 \u0431\u0435?", + "MessageDidYouKnowCinemaMode2": "\u041a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440 \u0440\u0435\u0436\u0456\u043c\u0456 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440\u0434\u0456 \u0436\u04d9\u043d\u0435 \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u043a\u04e9\u0440\u043d\u0435\u0443\u0434\u0456 \u043d\u0435\u0433\u0456\u0437\u0433\u0456 \u0444\u0438\u043b\u044c\u043c \u0430\u043b\u0434\u044b\u043d\u0434\u0430 \u043e\u0439\u043d\u0430\u0442\u0443 \u043a\u0438\u043d\u043e\u0437\u0430\u043b \u04d9\u0441\u0435\u0440\u0456\u043d \u0436\u0435\u0442\u043a\u0456\u0437\u0435\u0434\u0456.", + "HeaderPlayMyMedia": "\u041c\u0435\u043d\u0456\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043c\u0434\u0456 \u043e\u0439\u043d\u0430\u0442\u0443", + "HeaderDiscoverEmbyPremiere": "Emby Premiere \u0430\u0448\u044b\u04a3\u044b\u0437", + "Items": "\u0422\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440", + "OneChannel": "\u0411\u0456\u0440 \u0430\u0440\u043d\u0430\u0434\u0430\u043d", + "ConfirmRemoveDownload": "\u0416\u04af\u043a\u0442\u0435\u0443\u0434\u0456 \u0430\u043b\u0430\u0441\u0442\u0430\u0439\u043c\u044b\u0437 \u0431\u0430?", + "RemoveDownload": "\u0416\u04af\u043a\u0442\u0435\u0443\u0434\u0456 \u0430\u043b\u0430\u0441\u0442\u0430\u0443", + "KeepDownload": "\u0416\u04af\u043a\u0442\u0435\u0443\u0434\u0456 \u0441\u0430\u049b\u0442\u0430\u043f \u049b\u0430\u043b\u0443", + "AddedOnValue": "\u04ae\u0441\u0442\u0435\u043b\u0433\u0435\u043d\u0456 {0}", + "RemovingFromDevice": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443\u0434\u0430", + "KeepOnDevice": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430 \u0441\u0430\u049b\u0442\u0430\u043f \u049b\u0430\u043b\u0443", + "CancelDownload": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443\u0434\u044b \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443", + "SyncJobItemStatusReadyToTransfer": "\u0410\u0443\u044b\u0441\u0442\u044b\u0440\u044b\u043b\u0443\u0493\u0430 \u0434\u0430\u0439\u044b\u043d", + "SyncJobItemStatusSyncedMarkForRemoval": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443\u0434\u0430", + "SyncJobItemStatusQueued": "\u041a\u0435\u0437\u0435\u043a\u0442\u0435", + "SyncJobItemStatusConverting": "\u0422\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443\u0434\u0435", + "SyncJobItemStatusTransferring": "\u0410\u0443\u044b\u0441\u0442\u044b\u0440\u044b\u043b\u0443\u0434\u0430", + "SyncJobItemStatusSynced": "\u0416\u04af\u043a\u0442\u0435\u043b\u0456\u043f \u0430\u043b\u044b\u043d\u0434\u044b", + "SyncJobItemStatusFailed": "\u0421\u04d9\u0442\u0441\u0456\u0437", + "SyncJobItemStatusRemovedFromDevice": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0493\u0430\u043d", + "SyncJobItemStatusCancelled": "\u0411\u043e\u043b\u0434\u044b\u0440\u044b\u043b\u043c\u0430\u0434\u044b", + "Retry": "\u049a\u0430\u0439\u0442\u0430\u043b\u0430\u0443", + "HeaderMyDevice": "\u041c\u0435\u043d\u0456\u04a3 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043c", + "Continue": "\u0416\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443", + "ContinueInSecondsValue": "\u0416\u0430\u043b\u0493\u0430\u0441\u044b {0} \u0441 \u043a\u0435\u0439\u0456\u043d", + "HeaderRemoteControl": "\u049a\u0430\u0448\u044b\u049b\u0442\u0430\u043d \u0431\u0430\u0441\u049b\u0430\u0440\u0443", + "Disconnect": "\u0410\u0436\u044b\u0440\u0430\u0442\u0443", + "EnableDisplayMirroring": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u0443\u0434\u0456\u04a3 \u0442\u0435\u043b\u043d\u04b1\u0441\u049b\u0430\u0441\u044b\u043d \u049b\u043e\u0441\u0443", + "HeaderPlayOn": "\u041e\u0439\u043d\u0430\u0442\u0443\u0434\u044b \u049b\u043e\u0441\u0443", + "Quality": "\u0421\u0430\u043f\u0430\u0441\u044b", + "Auto": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b", + "AndroidUnlockRestoreHelp": "\u0410\u043b\u0434\u044b\u04a3\u0493\u044b \u0441\u0430\u0442\u044b\u043f \u0430\u043b\u0443\u0434\u044b \u049b\u0430\u043b\u043f\u044b\u043d\u0430 \u043a\u0435\u043b\u0442\u0456\u0440\u0443 \u04af\u0448\u0456\u043d, \u0431\u0430\u0441\u0442\u0430\u043f\u049b\u044b\u0434\u0430 \u0441\u0430\u0442\u044b\u043f \u0430\u043b\u0443 \u0436\u0430\u0441\u0430\u043b\u0493\u0430\u043d \u043d\u0430\u049b \u0441\u043e\u043b Google (\u043d\u0435\u043c\u0435\u0441\u0435 Amazon) \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456\u043c\u0435\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0493\u0430 \u043a\u0456\u0440\u0456\u04a3\u0456\u0437. \u049a\u043e\u043b\u0434\u0430\u043d\u0431\u0430 \u0434\u04af\u043a\u0435\u043d\u0456 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d \u0436\u04d9\u043d\u0435 \u043a\u0435\u0437 \u043a\u0435\u043b\u0433\u0435\u043d \u0430\u0442\u0430-\u0430\u043d\u0430 \u0448\u0435\u043a\u0442\u0435\u0443\u0441\u0456\u0437, \u0436\u04d9\u043d\u0435 \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b \u0431\u0430\u0440 \u0435\u043a\u0435\u043d\u0456\u043d\u0435 \u043a\u04e9\u0437 \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u04a3\u0456\u0437. \u0410\u043b\u0434\u044b\u04a3\u0493\u044b \u0441\u0430\u0442\u044b\u043f \u0430\u043b\u0443 \u049b\u0430\u043b\u043f\u044b\u043d\u0430 \u043a\u0435\u043b\u0442\u0456\u0440\u0443 \u04af\u0448\u0456\u043d \u043c\u04b1\u043d\u044b \u0442\u0435\u043a \u049b\u0430\u043d\u0430 \u0431\u0456\u0440 \u0440\u0435\u0442 \u0456\u0441\u0442\u0435\u0443 \u043a\u0435\u0440\u0435\u043a.", + "AspectRatio": "\u041f\u0456\u0448\u0456\u043c\u0434\u0456\u043a \u0430\u0440\u0430\u049b\u0430\u0442\u044b\u043d\u0430\u0441\u044b", + "Original": "\u0422\u04af\u043f\u043d\u04b1\u0441\u049b\u0430\u043b\u044b", + "Fill": "\u0422\u043e\u043b\u0442\u044b\u0440\u0443", + "BestFit": "\u049a\u0438\u044b\u0441\u0442\u044b\u0440\u0443", + "MessageNoServersAvailableToConnect": "\u049a\u043e\u0441\u044b\u043b\u0443 \u04af\u0448\u0456\u043d \u0435\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u0441\u0435\u0440\u0432\u0435\u0440\u043b\u0435\u0440 \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0435\u043c\u0435\u0441. \u0415\u0433\u0435\u0440 \u0441\u0435\u0440\u0432\u0435\u0440\u043c\u0435\u043d \u043e\u0440\u0442\u0430\u049b\u0442\u0430\u0441\u0443\u0493\u0430 \u0448\u0430\u049b\u044b\u0440\u044b\u043b\u0441\u0430\u04a3\u044b\u0437, \u049b\u0430\u0431\u044b\u043b\u0434\u0430\u0443\u044b\u043d \u0442\u04e9\u043c\u0435\u043d\u0434\u0435 \u043d\u0435\u043c\u0435\u0441\u0435 \u044d-\u043f\u043e\u0448\u0442\u0430\u0434\u0430\u0493\u044b \u0441\u0456\u043b\u0442\u0435\u043c\u0435\u043d\u0456 \u043d\u04b1\u049b\u044b\u043f \u043d\u0430\u049b\u0442\u044b\u043b\u0430\u04a3\u044b\u0437.", + "MessagePlayAccessRestricted": "\u041e\u0441\u044b \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b\u04a3 \u043e\u0439\u043d\u0430\u0442\u0443\u044b \u0430\u0493\u044b\u043c\u0434\u0430 \u0448\u0435\u043a\u0442\u0435\u043b\u0433\u0435\u043d. \u049a\u043e\u0441\u044b\u043c\u0448\u0430 \u0430\u049b\u043f\u0430\u0440\u0430\u0442 \u0430\u043b\u0443 \u04af\u0448\u0456\u043d Emby Server \u04d9\u043a\u0456\u043c\u0448\u0456\u0441\u0456\u043d\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.", + "Accept": "\u049a\u0430\u0431\u044b\u043b\u0434\u0430\u0443", + "Reject": "\u049a\u0430\u0431\u044b\u043b\u0434\u0430\u043c\u0430\u0443", + "Connect": "\u049a\u043e\u0441\u044b\u043b\u0443", + "HeaderMyMedia": "\u041c\u0435\u043d\u0456\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043c", + "HeaderMyMediaSmall": "\u041c\u0435\u043d\u0456\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043c (\u044b\u049b\u0448\u0430\u043c)", + "LatestFromLibrary": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 {0}", + "ContinueWatching": "\u049a\u0430\u0440\u0430\u0443\u0434\u044b \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443", + "HeaderLatestChannelMedia": "\u0410\u0440\u043d\u0430\u043b\u0430\u0440\u0434\u044b\u04a3 \u0435\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440\u044b", + "HeaderContinueWatching": "\u049a\u0430\u0440\u0430\u0443\u0434\u044b \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443", + "HeaderContinueListening": "\u0422\u044b\u04a3\u0434\u0430\u0443\u0434\u044b \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443", + "HeaderActiveRecordings": "\u0411\u0435\u043b\u0441\u0435\u043d\u0434\u0456 \u0436\u0430\u0437\u0431\u0430\u043b\u0430\u0440", + "HeaderLatestRecordings": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u04a3\u0433\u0456 \u0436\u0430\u0437\u0431\u0430\u043b\u0430\u0440", + "LabelSyncTo": "\u041e\u0441\u044b\u043c\u0435\u043d \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443:", + "LabelConvertTo": "\u041c\u044b\u043d\u0430\u0493\u0430\u043d \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443:", + "Next": "\u041a\u0435\u043b\u0435\u0441\u0456", + "LabelSource": "\u049a\u0430\u0439\u043d\u0430\u0440 \u043a\u04e9\u0437\u0456:", + "LabelVersion": "\u041d\u04b1\u0441\u049b\u0430:", + "AllLanguages": "\u0411\u0430\u0440\u043b\u044b\u049b \u0442\u0456\u043b\u0434\u0435\u0440", + "Previous": "\u0410\u043b\u0434\u044b\u04a3\u0493\u044b", + "HeaderNextUp": "\u041a\u0435\u0437\u0435\u043a\u0442\u0456", + "HeaderLatestFrom": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 {0}", + "LabelHomeScreenSectionValue": "\u0411\u0430\u0441\u0442\u044b \u0431\u0435\u0442 {0}-\u0431\u04e9\u043b\u0456\u043c:", + "SettingsSaved": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440 \u0441\u0430\u049b\u0442\u0430\u043b\u0434\u044b.", + "None": "\u0415\u0448\u049b\u0430\u043d\u0434\u0430\u0439", + "More": "\u041a\u04e9\u0431\u0456\u0440\u0435\u043a", + "Up": "\u0416\u043e\u0493\u0430\u0440\u044b\u0493\u0430", + "Down": "\u0422\u04e9\u043c\u0435\u043d\u0433\u0435", + "Home": "\u0411\u0430\u0441\u0442\u044b", + "Favorites": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b\u043b\u0430\u0440", + "HeaderHomeScreen": "\u0411\u0430\u0441\u0442\u044b \u044d\u043a\u0440\u0430\u043d", + "HeaderLatestChannelItems": "\u0410\u0440\u043d\u0430\u043b\u0430\u0440\u0434\u044b\u04a3 \u0435\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440\u044b", + "HeaderLibraryOrder": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430 \u0440\u0435\u0442\u0456", + "HideWatchedContentFromLatestMedia": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0435\u043d \u049b\u0430\u0440\u0430\u043b\u0493\u0430\u043d \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u0436\u0430\u0441\u044b\u0440\u0443", + "HeaderOnNow": "\u042d\u0444\u0438\u0440\u0434\u0435", + "HeaderPlaybackError": "\u041e\u0439\u043d\u0430\u0442\u0443 \u049b\u0430\u0442\u0435\u0441\u0456", + "PlaybackErrorNotAllowed": "\u041e\u0441\u044b \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u0430\u0493\u044b\u043c\u0434\u0430 \u0441\u0456\u0437\u0433\u0435 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0456\u043b\u043c\u0435\u0433\u0435\u043d. \u0422\u043e\u043b\u044b\u049b \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.", + "PlaybackErrorNoCompatibleStream": "\u0410\u0493\u044b\u043c\u0434\u0430 \u0435\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u0441\u044b\u0439\u044b\u0441\u044b\u043c\u0434\u044b \u0430\u0493\u044b\u043d\u0434\u0430\u0440 \u049b\u043e\u043b\u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0435\u043c\u0435\u0441. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0442\u043e\u043b\u044b\u049b \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.", + "PlaybackErrorPlaceHolder": "\u041e\u0441\u044b \u0431\u0435\u0439\u043d\u0435\u043d\u0456 \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u0434\u0438\u0441\u043a\u0456\u043d\u0456 \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437.", + "Guide": "\u0422\u0435\u043b\u0435\u0433\u0438\u0434", + "Suggestions": "\u04b0\u0441\u044b\u043d\u044b\u0441\u0442\u0430\u0440", + "HeaderFavoriteCollections": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b \u0436\u0438\u044b\u043d\u0442\u044b\u049b\u0442\u0430\u0440", + "HeaderFavoritePlaylists": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b \u043e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u0440\u0456", + "Collections": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b\u0442\u0430\u0440", + "LabelSelectFolderGroups": "\u041a\u0435\u043b\u0435\u0441\u0456 \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u0434\u0430\u0493\u044b \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u041a\u0438\u043d\u043e, \u041c\u0443\u0437\u044b\u043a\u0430 \u0436\u04d9\u043d\u0435 \u0422\u0414 \u0441\u0438\u044f\u049b\u0442\u044b \u0430\u0441\u043f\u0435\u043a\u0442\u0442\u0435\u0440\u0433\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u0442\u043e\u043f\u0442\u0430\u0441\u0442\u044b\u0440\u0443:", + "LabelSelectFolderGroupsHelp": "\u0411\u0435\u043b\u0433\u0456\u043b\u0435\u043d\u0431\u0435\u0433\u0435\u043d \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440 \u04e9\u0437 \u0431\u0435\u0442\u0456\u043c\u0435\u043d \u04e9\u0437\u0456\u043d\u0456\u04a3 \u0430\u0441\u043f\u0435\u043a\u0442\u0456\u043d\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0435\u0434\u0456.", + "Folders": "\u049a\u0430\u043b\u0442\u0430\u043b\u0430\u0440", + "DisplayInOtherHomeScreenSections": "\u0411\u0430\u0441\u0442\u044b \u044d\u043a\u0440\u0430\u043d \u0431\u04e9\u043b\u0456\u043c\u0434\u0435\u0440\u0456\u043d\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443 (\u043c\u044b\u0441. \u0415\u04a3 \u0441\u043e\u04a3\u0493\u044b \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0436\u04d9\u043d\u0435 \u041a\u04e9\u0440\u0443\u0434\u0456 \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443)", + "DisplayInMyMedia": "\u0411\u0430\u0441\u0442\u044b \u044d\u043a\u0440\u0430\u043d\u0434\u0430 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0435\u0434\u0456", + "Shows": "\u041a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c\u0434\u0435\u0440", + "HeaderLibraryFolders": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u043b\u044b\u049b \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440", + "HeaderTermsOfPurchase": "\u0421\u0430\u0442\u044b\u043f \u0430\u043b\u0443 \u0448\u0430\u0440\u0442\u0442\u0430\u0440\u044b", + "PrivacyPolicy": "\u049a\u04b1\u043f\u0438\u044f\u043b\u044b\u043b\u044b\u049b \u0441\u0430\u044f\u0441\u0430\u0442\u044b", + "TermsOfUse": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443 \u0448\u0430\u0440\u0442\u0442\u0430\u0440\u044b", + "RepeatMode": "\u049a\u0430\u0439\u0442\u0430\u043b\u0430\u0443 \u0440\u0435\u0436\u0456\u043c\u0456", + "RepeatOne": "\u0411\u0456\u0440 \u0440\u0435\u0442 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u0443", + "RepeatAll": "\u0411\u0430\u0440\u043b\u044b\u0493\u044b\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u0443", + "LabelDefaultScreen": "\u04d8\u0434\u0435\u043f\u043a\u0456 \u044d\u043a\u0440\u0430\u043d:", + "ConfirmEndPlayerSession": "Emby \u0436\u04b1\u043c\u044b\u0441\u044b\u043d \u0430\u044f\u049b\u0442\u0430\u0443\u0434\u044b {0} \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430 \u049b\u0430\u043b\u0430\u0439\u0441\u044b\u0437 \u0431\u0430?", + "Yes": "\u0418\u04d9", + "No": "\u0416\u043e\u049b", + "LiveTV": "\u042d\u0444\u0438\u0440", + "Schedule": "\u0406\u0441 \u043a\u0435\u0441\u0442\u0435\u0441\u0456", + "Recordings": "\u0416\u0430\u0437\u0431\u0430\u043b\u0430\u0440", + "MarkWatched": "\u049a\u0430\u0440\u0430\u043f \u0448\u044b\u049b\u049b\u0430\u043d", + "ScanForNewAndUpdatedFiles": "\u0416\u0430\u04a3\u0430 \u0436\u04d9\u043d\u0435 \u0436\u0430\u04a3\u0430\u0440\u0442\u044b\u043b\u0493\u0430\u043d \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u0434\u044b \u0441\u043a\u0430\u043d\u0435\u0440\u043b\u0435\u0443", + "DirectStreamHelp1": "\u0410\u0436\u044b\u0440\u0430\u0442\u044b\u043c\u0434\u044b\u043b\u044b\u049b \u043f\u0435\u043d \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0442\u04af\u0440\u0456\u043d\u0435 (H.264, AC3, \u0442.\u0431.) \u049b\u0430\u0442\u044b\u0441\u0442\u044b \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0493\u0430 \u0441\u04d9\u0439\u043a\u0435\u0441 \u043a\u0435\u043b\u0435\u0434\u0456, \u0431\u0456\u0440\u0430\u049b \u0441\u044b\u0439\u044b\u0441\u043f\u0430\u0439\u0442\u044b\u043d \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0456\u043d\u0434\u0435 (.mkv, .avi, .wmv \u0436\u04d9\u043d\u0435 \u0442.\u0431.) \u0431\u043e\u043b\u044b\u043f \u0442\u04b1\u0440. \u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u0493\u0430 \u0442\u0430\u0440\u0430\u0442\u043f\u0430\u0441 \u0431\u04b1\u0440\u044b\u043d, \u0431\u0435\u0439\u043d\u0435 \u043d\u0430\u049b\u0442\u044b \u0443\u0430\u049b\u044b\u0442\u0442\u0430 \u049b\u0430\u0439\u0442\u0430 \u0436\u0438\u043d\u0430\u049b\u0442\u0430\u043b\u0430\u0434\u044b.", + "DirectStreamHelp2": "\u0424\u0430\u0439\u043b\u0434\u044b \u0442\u0456\u043a\u0435\u043b\u0435\u0439 \u0442\u0430\u0440\u0430\u0442\u0443 \u0431\u0435\u0439\u043d\u0435 \u0441\u0430\u043f\u0430\u0441\u044b\u043d \u0436\u043e\u0493\u0430\u043b\u0442\u043f\u0430\u0439 \u04e9\u0442\u0435 \u0430\u0437 \u0435\u0441\u0435\u043f\u0442\u0435\u0443 \u049b\u0443\u0430\u0442\u044b\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0430\u0434\u044b.", + "MediaIsBeingConverted": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043e\u0439\u043d\u0430\u0442\u0443\u0448\u044b \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043c\u0435\u043d \u04af\u0439\u043b\u0435\u0441\u0456\u043c\u0434\u0456 \u043f\u0456\u0448\u0456\u043c\u0433\u0435 \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0456\u043b\u0435\u0434\u0456.", + "StatsForNerds": "\u0410\u049b\u044b\u043b\u0433\u04e9\u0439\u043b\u0435\u0440 \u04af\u0448\u0456\u043d \u0441\u0430\u043d\u0430\u049b", + "LabelReasonForTranscoding": "\u049a\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443 \u0441\u0435\u0431\u0435\u0431\u0456:", + "DirectPlaying": "\u0422\u0456\u043a\u0435\u043b\u0435\u0439 \u043e\u0439\u043d\u0430\u0442\u0443\u0434\u0430", + "DirectStreaming": "\u0422\u0456\u043a\u0435\u043b\u0435\u0439 \u0442\u0430\u0441\u044b\u043c\u0430\u043b\u0434\u0430\u043d\u0443\u0434\u0430", + "Transcoding": "\u049a\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443\u0434\u0430", + "ContainerBitrateExceedsLimit": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u049b\u0430\u0440\u049b\u044b\u043d\u044b \u0448\u0435\u0433\u0456\u043d\u0435\u043d \u0430\u0440\u0442\u0442\u044b.", + "VideoCodecNotSupported": "\u0411\u0435\u0439\u043d\u0435 \u043a\u043e\u0434\u0435\u043a \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "AudioCodecNotSupported": "\u0414\u044b\u0431\u044b\u0441 \u043a\u043e\u0434\u0435\u043a \u049b\u043e\u043b\u0434\u0430\u0443\u0434\u0430 \u0435\u043c\u0435\u0441", + "SubtitleCodecNotSupported": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u043f\u0456\u0448\u0456\u043c \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "DirectPlayError": "\u0422\u0456\u043a\u0435\u043b\u0435\u0439 \u043e\u0439\u043d\u0430\u0442\u0443 \u049b\u0430\u0442\u0435\u0441\u0456", + "ContainerNotSupported": "\u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "VideoLevelNotSupported": "\u0411\u0435\u0439\u043d\u0435 \u0434\u0435\u04a3\u0433\u0435\u0439\u0456 \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "AudioBitrateNotSupported": "\u0414\u044b\u0431\u044b\u0441 \u049b\u0430\u0440\u049b\u044b\u043d\u044b \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "AudioChannelsNotSupported": "\u0414\u044b\u0431\u044b\u0441 \u0430\u0440\u043d\u0430\u043b\u0430\u0440\u044b \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "VideoResolutionNotSupported": "\u0411\u0435\u0439\u043d\u0435 \u0430\u0436\u044b\u0440\u0430\u0442\u044b\u043b\u044b\u043c\u0434\u044b\u0493\u044b \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "AudioProfileNotSupported": "\u0414\u044b\u0431\u044b\u0441 \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u044b \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "AudioSampleRateNotSupported": "\u04ae\u043b\u0433\u0456 \u0436\u0438\u0456\u043b\u0456\u0433\u0456 \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "AnamorphicVideoNotSupported": "\u0410\u043d\u0430\u043c\u043e\u0440\u0444\u0442\u044b\u049b \u0431\u0435\u0439\u043d\u0435 \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "InterlacedVideoNotSupported": "\u041a\u0435\u0437\u0435\u043a\u0442\u0435\u0441\u0443\u043b\u0456\u043a \u0431\u0435\u0439\u043d\u0435 \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "SecondaryAudioNotSupported": "\u0414\u044b\u0431\u044b\u0441 \u0436\u043e\u043b\u0448\u044b\u0493\u044b\u043d \u0430\u0443\u044b\u0441\u0442\u044b\u0440\u0443 \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "ErrorRemovingEmbyConnectAccount": "Emby Connect \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u0411\u0435\u043b\u0441\u0435\u043d\u0434\u0456 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u049b\u043e\u0441\u044b\u043b\u044b\u043c\u044b \u0431\u0430\u0440 \u0435\u043a\u0435\u043d\u0456\u043d\u0435 \u043a\u04e9\u0437 \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u04a3\u0456\u0437 \u0436\u04d9\u043d\u0435 \u04d9\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.", + "HeaderEmbyAccountRemoved": "Emby \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456 \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0434\u044b", + "MessageEmbyAccontRemoved": "Emby \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456 \u043e\u0441\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u044b\u043d\u0434\u044b.", + "HeaderInvitationSent": "\u0428\u0430\u049b\u044b\u0440\u0443 \u0436\u0456\u0431\u0435\u0440\u0456\u043b\u0434\u0456", + "MessageInvitationSentToUser": "\u041e\u043b\u0430\u0440\u0493\u0430 \u043e\u0440\u0442\u0430\u049b\u0442\u0430\u0441\u0443 \u0448\u0430\u049b\u044b\u0440\u0443\u044b\u04a3\u044b\u0437\u0434\u044b \u049b\u0430\u0431\u044b\u043b\u0434\u0430\u0443 \u04b1\u0441\u044b\u043d\u044b\u0441\u044b\u043c\u0435\u043d, \u044d-\u043f\u043e\u0448\u0442\u0430 {0} \u0430\u0440\u043d\u0430\u043f \u0436\u0456\u0431\u0435\u0440\u0456\u043b\u0434\u0456.", + "MessageInvitationSentToNewUser": "Emby \u04af\u0448\u0456\u043d \u0442\u0456\u0440\u043a\u0435\u043b\u0443 \u0448\u0430\u049b\u044b\u0440\u0443\u044b\u04a3\u044b\u0437, \u044d-\u043f\u043e\u0448\u0442\u0430 {0} \u04af\u0448\u0456\u043d \u0436\u0456\u0431\u0435\u0440\u0456\u043b\u0434\u0456.", + "GuestUserNotFound": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0442\u0430\u0431\u044b\u043b\u0493\u0430\u043d \u0436\u043e\u049b. \u0410\u0442\u044b\u043d\u044b\u04a3 \u0434\u04b1\u0440\u044b\u0441\u0442\u044b\u0493\u044b\u043d \u0442\u0435\u043a\u0441\u0435\u0440\u0456\u04a3\u0456\u0437 \u0436\u04d9\u043d\u0435 \u04d9\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437, \u043d\u0435\u043c\u0435\u0441\u0435 \u043e\u043d\u044b\u04a3 \u044d-\u043f\u043e\u0448\u0442\u0430 \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439\u044b\u043d \u0435\u043d\u0433\u0456\u0437\u0456\u043f \u043a\u04e9\u0440\u0456\u04a3\u0456\u0437.", + "ErrorReachingEmbyConnect": "Emby Connect \u0441\u0435\u0440\u0432\u0435\u0440\u0456\u043d\u0435 \u0436\u0435\u0442\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u0411\u0435\u043b\u0441\u0435\u043d\u0434\u0456 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u049b\u043e\u0441\u044b\u043b\u044b\u043c\u044b \u0431\u0430\u0440 \u0435\u043a\u0435\u043d\u0456\u043d\u0435 \u043a\u04e9\u0437 \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u04a3\u0456\u0437 \u0436\u04d9\u043d\u0435 \u04d9\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.", + "ErrorAddingEmbyConnectAccount1": "Emby Connect \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456\u043d \u04af\u0441\u0442\u0435\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. Emby \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456\u043d \u0436\u0430\u0441\u0430\u0434\u044b\u04a3\u044b\u0437 \u0431\u0430? {0} \u0436\u0430\u043d\u044b\u043d\u0434\u0430 \u0442\u0456\u0440\u043a\u0435\u043b\u0456\u04a3\u0456\u0437.", + "ErrorAddingEmbyConnectAccount2": "\u0415\u0433\u0435\u0440 \u04d9\u043b\u0456 \u0434\u0435 \u043c\u04d9\u0441\u0435\u043b\u0435\u04a3\u0456\u0437 \u0431\u043e\u043b\u0441\u0430, Emby \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456\u043d\u0434\u0435 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u043b\u0493\u0430\u043d \u044d-\u043f\u043e\u0448\u0442\u0430 \u0430\u0440\u049b\u044b\u043b\u044b {0} \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439\u044b\u043d\u0430 \u0445\u0430\u0431\u0430\u0440 \u0436\u0456\u0431\u0435\u0440\u0456\u04a3\u0456\u0437.", + "ErrorAddingGuestAccount1": "Emby Connect \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456\u043d \u04af\u0441\u0442\u0435\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u049a\u043e\u043d\u0430\u0493\u044b\u04a3\u044b\u0437 Emby \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456\u043d \u0436\u0430\u0441\u0430\u0434\u044b \u043c\u0430? \u041e\u043b {0} \u0436\u0430\u043d\u044b\u043d\u0434\u0430 \u0442\u0456\u0440\u043a\u0435\u043b\u0443\u0456 \u043c\u04af\u043c\u043a\u0456\u043d.", + "ErrorAddingGuestAccount2": "\u0415\u0433\u0435\u0440 \u04d9\u043b\u0456 \u0434\u0435 \u043c\u04d9\u0441\u0435\u043b\u0435\u04a3\u0456\u0437 \u0431\u043e\u043b\u0441\u0430, \u04e9\u0437\u0456\u04a3\u0456\u0437\u0434\u0456\u04a3 \u0436\u04d9\u043d\u0435 \u043e\u043b\u0430\u0440\u0434\u044b\u04a3 \u044d-\u043f\u043e\u0448\u0442\u0430 \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439\u043b\u0430\u0440\u044b\u043d \u049b\u043e\u0441\u044b\u043f \u044d-\u043f\u043e\u0448\u0442\u0430 \u0430\u0440\u049b\u044b\u043b\u044b {0} \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439\u044b\u043d\u0430 \u0445\u0430\u0431\u0430\u0440 \u0436\u0456\u0431\u0435\u0440\u0456\u04a3\u0456\u0437.", + "MessageEmbyAccountAdded": "Emby \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456 \u043e\u0441\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u0433\u0430 \u04af\u0441\u0442\u0435\u043b\u0456\u043d\u0434\u0456.", + "MessagePendingEmbyAccountAdded": "Emby \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456 \u043e\u0441\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u0433\u0430 \u04af\u0441\u0442\u0435\u043b\u0456\u043d\u0434\u0456. \u0422\u0456\u0440\u043a\u0435\u043b\u0433\u0456 \u0438\u0435\u0441\u0456\u043d\u0435 \u044d-\u043f\u043e\u0448\u0442\u0430 \u0436\u0456\u0431\u0435\u0440\u0456\u043b\u0435\u0434\u0456. \u042d-\u043f\u043e\u0448\u0442\u0430\u0434\u0430\u0493\u044b \u0441\u0456\u043b\u0442\u0435\u043c\u0435\u043d\u0456 \u043d\u04b1\u049b\u044b\u043f \u0448\u0430\u049b\u044b\u0440\u0443\u0434\u044b \u0440\u0430\u0441\u0442\u0430\u0443 \u049b\u0430\u0436\u0435\u0442 \u0431\u043e\u043b\u0430\u0434\u044b.", + "HeaderEmbyAccountAdded": "Emby \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456 \u04af\u0441\u0442\u0435\u043b\u0456\u043d\u0434\u0456", + "LabelSubtitlePlaybackMode": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440 \u0440\u0435\u0436\u0456\u043c\u0456:", + "ErrorDeletingItem": "Emby Server \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0456\u043d \u0436\u043e\u044e \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. Emby Server \u0442\u0430\u0441\u044b\u0493\u044b\u0448 \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d\u0430 \u0436\u0430\u0437\u0443\u0493\u0430 \u0440\u04b1\u049b\u0441\u0430\u0442\u044b \u0431\u0430\u0440 \u0435\u043a\u0435\u043d\u0456\u043d \u0442\u0435\u043a\u0441\u0435\u0440\u0456\u043f, \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u043f \u043a\u04e9\u0440\u0456\u04a3\u0456\u0437.", + "NoSubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0441\u0456\u0437", + "Default": "\u04d8\u0434\u0435\u043f\u043a\u0456", + "Absolute": "\u0422\u04af\u043f\u043d\u04b1\u0441\u049b\u0430\u043b\u044b\u049b", + "Smart": "\u0417\u0438\u044f\u0442\u0442\u044b", + "Small": "\u04b0\u0441\u0430\u049b", + "Smaller": "\u041a\u0456\u0448\u0456\u0433\u0456\u0440\u0456\u043c", + "Medium": "\u041e\u0440\u0442\u0430\u0448\u0430", + "Large": "\u0406\u0440\u0456", + "ExtraLarge": "\u04e8\u0442\u0435 \u0456\u0440\u0456", + "OnlyForcedSubtitles": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u043c\u04d9\u0436\u0431\u04af\u0440\u043b\u0456 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440", + "AlwaysPlaySubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0434\u0456 \u04d9\u0440\u049b\u0430\u0448\u0430\u043d \u043e\u0439\u043d\u0430\u0442\u0443", + "DefaultSubtitlesHelp": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0435\u043d\u0433\u0456\u0437\u0456\u043b\u0433\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0435\u0433\u0456 \u04d9\u0434\u0435\u043f\u043a\u0456 \u0436\u04d9\u043d\u0435 \u043c\u04d9\u0436\u0431\u04af\u0440\u043b\u0456 \u0436\u0430\u043b\u0430\u0443\u0448\u0430\u043b\u0430\u0440\u044b \u043d\u0435\u0433\u0456\u0437\u0456\u043d\u0434\u0435 \u0436\u04af\u043a\u0442\u0435\u043b\u0456\u043f \u0430\u043b\u044b\u043d\u0430\u0434\u044b. \u0411\u0456\u0440\u043d\u0435\u0448\u0435 \u043e\u043f\u0446\u0438\u044f \u049b\u043e\u043b\u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0493\u0430\u043d\u0434\u0430 \u0442\u0456\u043b \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456 \u049b\u0430\u0440\u0430\u0441\u0442\u044b\u0440\u044b\u043b\u0430\u0434\u044b.", + "SmartSubtitlesHelp": "\u0422\u0456\u043b \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456\u043d\u0435 \u0441\u04d9\u0439\u043a\u0435\u0441 \u043a\u0435\u043b\u0433\u0435\u043d \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0434\u044b\u0431\u044b\u0441 \u0448\u0435\u0442\u0435\u043b \u0442\u0456\u043b\u0456\u043d\u0434\u0435 \u0431\u043e\u043b\u0493\u0430\u043d\u0434\u0430 \u0436\u04af\u043a\u0442\u0435\u043b\u0435\u0434\u0456.", + "HeaderSubtitleSettings": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456", + "HeaderSubtitleAppearance": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u043a\u04e9\u0440\u0456\u043d\u0456\u0441\u0456", + "OnlyForcedSubtitlesHelp": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u043c\u04d9\u0436\u0431\u04af\u0440\u043b\u0456 \u0434\u0435\u043f \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u043d\u0433\u0435\u043d \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0436\u04af\u043a\u0442\u0435\u043b\u0435\u0434\u0456.", + "AlwaysPlaySubtitlesHelp": "\u0422\u0456\u043b \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456\u043d\u0435 \u0441\u04d9\u0439\u043a\u0435\u0441 \u043a\u0435\u043b\u0433\u0435\u043d \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0434\u044b\u0431\u044b\u0441 \u0442\u0456\u043b\u0456\u043d\u0435 \u049b\u0430\u0442\u044b\u0441\u0441\u044b\u0437 \u0436\u04af\u043a\u0442\u0435\u043b\u0435\u0434\u0456.", + "NoSubtitlesHelp": "\u04d8\u0434\u0435\u043f\u043a\u0456\u0434\u0435 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0436\u04af\u043a\u0442\u0435\u043b\u043c\u0435\u0439\u0434\u0456. \u041e\u043b\u0430\u0440\u0434\u044b \u043e\u0439\u043d\u0430\u0442\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u04d9\u043b\u0456 \u0434\u0435 \u049b\u043e\u043b\u043c\u0435\u043d \u049b\u043e\u0441\u0443\u0493\u0430 \u0431\u043e\u043b\u0430\u0434\u044b.", + "LabelPreferredSubtitleLanguage": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440 \u0442\u0456\u043b\u0456\u043d\u0456\u04a3 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456:", + "LabelTextSize": "\u041c\u04d9\u0442\u0456\u043d \u04e9\u043b\u0448\u0435\u043c\u0456:", + "TheseSettingsAffectSubtitlesOnThisDevice": "\u0411\u04b1\u043b \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440 \u043e\u0441\u044b \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u0493\u044b \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0433\u0435 \u04d9\u0441\u0435\u0440 \u0435\u0442\u0435\u0434\u0456", + "LabelDropShadow": "\u0416\u0438\u0435\u043a\u0442\u0435\u0440:", + "LabelTextBackgroundColor": "\u041c\u04d9\u0442\u0456\u043d \u04e9\u04a3\u0456\u043d\u0456\u04a3 \u0442\u04af\u0441\u0456:", + "LabelWindowBackgroundColor": "\u0422\u0435\u0440\u0435\u0437\u0435 \u04e9\u04a3\u0456\u043d\u0456\u04a3 \u0442\u04af\u0441\u0456:", + "LabelFont": "\u049a\u0430\u0440\u0456\u043f:", + "LabelTextColor": "\u041c\u04d9\u0442\u0456\u043d \u0442\u04af\u0441\u0456:", + "Raised": "\u041a\u04e9\u0442\u0435\u0440\u0456\u043b\u0433\u0435\u043d", + "Depressed": "\u0422\u04e9\u043c\u0435\u043d \u0442\u04af\u0441\u0456\u0440\u0456\u043b\u0433\u0435\u043d", + "Uniform": "\u0411\u0456\u0440\u044b\u04a3\u0493\u0430\u0439", + "DropShadow": "\u041a\u04e9\u043b\u0435\u04a3\u043a\u0435\u043b\u0456", + "SmallCaps": "\u041a\u0456\u0448\u0456 \u0431\u0430\u0441 \u04d9\u0440\u0456\u043f\u0442\u0435\u0440", + "SubtitleAppearanceSettingsDisclaimer": "\u0411\u04b1\u043b \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440 \u0433\u0440\u0430\u0444\u0438\u043a\u0430\u043b\u044b\u049b \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0433\u0435 (PGS, DVD \u0436.\u0442.\u0431.) \u043d\u0435\u043c\u0435\u0441\u0435 \u04e9\u0437 \u043c\u04d9\u043d\u0435\u0440\u0456 \u0431\u0430\u0440 \u0435\u043d\u0434\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0433\u0435 (ASS\/SSA) \u049b\u043e\u043b\u0434\u0430\u043d\u044b\u043b\u043c\u0430\u0439\u0434\u044b.", + "LabelBurnSubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0434\u0456 \u0436\u0430\u0437\u0443:", + "OnlyImageFormats": "\u0422\u0435\u043a \u043a\u0435\u0441\u043a\u0456\u043d \u043f\u0456\u0448\u0456\u043c\u0434\u0435\u0440\u0456 (VOBSUB, PGS, SUB\/IDX \u0436\u04d9\u043d\u0435 \u0442.\u0431. )", + "Normal": "\u041a\u04d9\u0434\u0456\u043c\u0433\u0456", + "BurnSubtitlesHelp": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u043f\u0456\u0448\u0456\u043c\u0456\u043d\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u044b \u0431\u0435\u0439\u043d\u0435\u043d\u0456 \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0433\u0435\u043d \u043a\u0435\u0437\u0434\u0435 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0434\u0456 \u0436\u0430\u0437\u044b\u0443\u044b\u043d \u0430\u043d\u044b\u049b\u0442\u0430\u0439\u0434\u044b. \u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0436\u0430\u0437\u0443\u0434\u044b \u049b\u0430\u0448\u049b\u0430\u049b\u0442\u0430\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0456\u04a3 \u04e9\u043d\u0456\u043c\u0434\u0456\u043b\u0456\u0433\u0456\u043d \u0436\u0430\u049b\u0441\u0430\u0440\u0442\u0430\u0434\u044b. \u0421\u0443\u0440\u0435\u0442\u043a\u0435 \u043d\u0435\u0433\u0456\u0437\u0434\u0435\u043b\u0433\u0435\u043d \u043f\u0456\u0448\u0456\u043c\u0434\u0435\u0440\u0434\u0456 (\u043c\u044b\u0441\u0430\u043b\u044b, VOBSUB, PGS, SUB\/IDX \u0436.\u0442.\u0431.), \u0441\u043e\u043d\u0434\u0430\u0439-\u0430\u049b \u043a\u0435\u0439\u0431\u0456\u0440 ASS\/SSA \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440\u0456\u043d \u0436\u0430\u0437\u0443 \u04af\u0448\u0456\u043d \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b\u043d\u044b \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437", + "AllComplexFormats": "\u0411\u0430\u0440\u043b\u044b\u049b \u043a\u04af\u0440\u0434\u0435\u043b\u0456 \u043f\u0456\u0448\u0456\u043c\u0434\u0435\u0440\u0456 (ASS, SSA, VOBSUB, PGS, SUB\/IDX \u0436\u04d9\u043d\u0435 \u0442.\u0431.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "\u0411\u04b1\u043b \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440 \u043e\u0441\u044b \u049b\u04b1\u0440\u044b\u043b\u0493\u044b \u0430\u0440\u049b\u044b\u043b\u044b \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d \u043a\u0435\u0437-\u043a\u0435\u043b\u0433\u0435\u043d Chromecast \u043e\u0439\u043d\u0430\u0442\u0443\u044b\u043d\u0430 \u049b\u043e\u043b\u0434\u0430\u043d\u044b\u043b\u0430\u0434\u044b.", + "HeaderWaitingForWifi": "WiFi \u04af\u0448\u0456\u043d \u043a\u04af\u0442\u0443\u0434\u0435", + "WifiRequiredToDownload": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443\u0434\u044b \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443 \u04af\u0448\u0456\u043d WiFi \u049b\u043e\u0441\u044b\u043b\u044b\u043c\u044b \u049b\u0430\u0436\u0435\u0442.", + "HeaderDownloadSettings": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456", + "Hide": "\u0416\u0430\u0441\u044b\u0440\u0443", + "HeaderStartNow": "\u049a\u0430\u0437\u0456\u0440 \u0431\u0430\u0441\u0442\u0430\u0443", + "HeaderNextVideoPlayingInValue": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0431\u0435\u0439\u043d\u0435 {0} \u0456\u0448\u0456\u043d\u0434\u0435 \u043e\u0439\u043d\u0430\u0442\u044b\u043b\u0430\u0434\u044b", + "HeaderNextEpisodePlayingInValue": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0431\u04e9\u043b\u0456\u043c {0} \u0456\u0448\u0456\u043d\u0434\u0435 \u043e\u0439\u043d\u0430\u0442\u044b\u043b\u0430\u0434\u044b", + "HeaderSecondsValue": "{0} \u0441\u0435\u043a\u04e9\u043d\u0434", + "AudioBitDepthNotSupported": "\u0414\u044b\u0431\u044b\u0441\u0442\u044b\u04a3 \u0431\u0438\u0442\u0442\u0456\u043a \u0442\u0435\u0440\u0435\u04a3\u0434\u0456\u0433\u0456 \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "VideoProfileNotSupported": "\u0411\u0435\u0439\u043d\u0435 \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u044b \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "VideoFramerateNotSupported": "\u0411\u0435\u0439\u043d\u0435\u043d\u0456\u04a3 \u043a\u0430\u0434\u0440 \u0436\u044b\u043b\u0434\u0430\u043c\u0434\u044b\u0493\u044b \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "VideoBitDepthNotSupported": "\u0411\u0435\u0439\u043d\u0435\u043d\u0456\u04a3 \u0431\u0438\u0442\u0442\u0456\u043a \u0442\u0435\u0440\u0435\u04a3\u0434\u0456\u0433\u0456 \u04af\u0448\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "RefFramesNotSupported": "\u0411\u0435\u0439\u043d\u0435\u043d\u0456\u04a3 \u0442\u0456\u0440\u0435\u043a \u043a\u0430\u0434\u0440\u043b\u0430\u0440 \u0441\u0430\u043d\u044b\u043d\u0430 \u049b\u043e\u043b\u0434\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0439\u0434\u0456", + "ErrorConnectServerUnreachable": "\u0421\u04b1\u0440\u0430\u043b\u0493\u0430\u043d \u04d9\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043e\u0440\u044b\u043d\u0434\u0430\u0443\u0434\u0430 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u0421\u0435\u0440\u0432\u0435\u0440\u0456\u04a3\u0456\u0437 {0} \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439\u044b\u043d\u0434\u0430\u0493\u044b Embo Connect Server \u0442\u0430\u0440\u0430\u043f\u044b\u043d\u0430 \u049b\u0430\u0442\u044b\u043d\u0430\u0441\u0430 \u0430\u043b\u043c\u0430\u0434\u044b. \u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0435 \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u049b\u043e\u0441\u044b\u043b\u044b\u043c\u044b \u0431\u0430\u0440 \u0435\u043a\u0435\u043d\u0456\u043d \u0436\u04d9\u043d\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441 \u049b\u0430\u0439 \u049b\u0430\u0439\u0441\u044b\u0441\u044b \u0431\u0440\u0430\u043d\u0434\u043c\u0430\u0443\u044d\u0440 \u043d\u0435\u043c\u0435\u0441\u0435 \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u0493\u0430\u043d \u049b\u0430\u0443\u0456\u043f\u0441\u0456\u0437\u0434\u0456\u043a \u0431\u0430\u0493\u0434\u0430\u0440\u043b\u0430\u043c\u0430\u043b\u044b\u049b \u0436\u0430\u0441\u0430\u049b\u0442\u0430\u043c\u0430 \u0430\u0440\u049b\u044b\u043b\u044b \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0456\u043b\u0443\u0456\u043d\u0435 \u043a\u04e9\u0437 \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u04a3\u0456\u0437.", + "StopRecording": "\u0416\u0430\u0437\u0443\u0434\u044b \u0442\u043e\u049b\u0442\u0430\u0442\u0443", + "HeaderStopRecording": "\u0416\u0430\u0437\u0443\u0434\u044b \u0442\u043e\u049b\u0442\u0430\u0442\u0443", + "ManageRecording": "\u0416\u0430\u0437\u0443\u0434\u044b \u0440\u0435\u0442\u0442\u0435\u0443", + "LabelDropImageHere": "\u0421\u0443\u0440\u0435\u0442\u0442\u0456 \u043c\u04b1\u043d\u0434\u0430 \u0441\u04af\u0439\u0440\u0435\u0442\u0456\u04a3\u0456\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0448\u0430\u0440\u043b\u0430\u0443 \u04af\u0448\u0456\u043d \u043d\u04b1\u049b\u044b\u04a3\u044b\u0437.", + "MessageFileReadError": "\u0424\u0430\u0439\u043b \u043e\u049b\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.", + "Browse": "\u0428\u0430\u0440\u043b\u0430\u0443", + "HeaderUploadImage": "\u0421\u0443\u0440\u0435\u0442\u0442\u0456 \u0436\u04af\u043a\u0442\u0435\u043f \u0431\u0435\u0440\u0443", + "HeaderAddUpdateImage": "\u0421\u0443\u0440\u0435\u0442\u0442\u0456 \u04af\u0441\u0442\u0435\u0443\/\u0436\u0430\u04a3\u0430\u0440\u0442\u0443", + "LabelImageType": "\u0421\u0443\u0440\u0435\u0442 \u0442\u04af\u0440\u0456:", + "Upload": "\u041a\u0435\u0440\u0456 \u049b\u043e\u0442\u0430\u0440\u0443", + "Primary": "\u041d\u0435\u0433\u0456\u0437\u0433\u0456", + "Art": "\u041e\u044e \u0441\u0443\u0440\u0435\u0442", + "Backdrop": "\u0410\u0440\u0442\u049b\u044b \u0441\u0443\u0440\u0435\u0442", + "Banner": "\u0411\u0430\u043d\u043d\u0435\u0440", + "Box": "\u049a\u043e\u0440\u0430\u043f", + "BoxRear": "\u049a\u043e\u0440\u0430\u043f \u0430\u0440\u0442\u044b", + "Disc": "\u0414\u0438\u0441\u043a\u0456", + "Logo": "\u041b\u043e\u0433\u043e\u0442\u0438\u043f", + "Menu": "\u041c\u04d9\u0437\u0456\u0440", + "Screenshot": "\u042d\u043a\u0440\u0430\u043d \u0441\u0443\u0440\u0435\u0442\u0456", + "Thumb": "\u041d\u043e\u0431\u0430\u0439", + "ValueSeconds": "{0} \u0441\u0435\u043a", + "HeaderAudioSettings": "\u0414\u044b\u0431\u044b\u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456", + "LabelAudioLanguagePreference": "\u0414\u044b\u0431\u044b\u0441 \u0442\u0456\u043b\u0456\u043d\u0456\u04a3 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456:", + "LabelPlayDefaultAudioTrack": "\u0422\u0456\u043b\u0433\u0435 \u049b\u0430\u0442\u044b\u0441\u0441\u044b\u0437 \u04d9\u0434\u0435\u043f\u043a\u0456 \u0434\u044b\u0431\u044b\u0441 \u0436\u043e\u043b\u0448\u044b\u0493\u044b\u043d \u043e\u0439\u043d\u0430\u0442\u0443", + "HeaderVideoQuality": "\u0411\u0435\u0439\u043d\u0435 \u0441\u0430\u043f\u0430\u0441\u044b", + "CinemaModeConfigurationHelp": "\u041a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440 \u0440\u0435\u0436\u0456\u043c\u0456 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440\u0434\u0456 \u0436\u04d9\u043d\u0435 \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u043a\u04e9\u0440\u043d\u0435\u0443\u0434\u0456 \u043d\u0435\u0433\u0456\u0437\u0433\u0456 \u0444\u0438\u043b\u044c\u043c \u0430\u043b\u0434\u044b\u043d\u0434\u0430 \u043e\u0439\u043d\u0430\u0442\u0443 \u043a\u0438\u043d\u043e\u0437\u0430\u043b \u04d9\u0441\u0435\u0440\u0456\u043d \u0436\u0435\u0442\u043a\u0456\u0437\u0435\u0434\u0456.", + "EnableNextVideoInfoOverlay": "\u041e\u0439\u043d\u0430\u0442\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u043a\u0435\u043b\u0435\u0441\u0456 \u0431\u0435\u0439\u043d\u0435 \u0442\u0443\u0440\u0430\u043b\u044b \u0430\u049b\u043f\u0430\u0440\u0430\u0442\u0442\u044b \u049b\u043e\u0441\u0443", + "EnableNextVideoInfoOverlayHelp": "\u0411\u0435\u0439\u043d\u0435 \u0441\u043e\u04a3\u044b\u043d\u0434\u0430 \u0430\u0493\u044b\u043c\u0434\u0430\u0493\u044b \u043e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0456\u043d\u0434\u0435\u0433\u0456 \u043a\u0435\u043b\u0435\u0441\u0456 \u0431\u0435\u0439\u043d\u0435 \u0442\u0443\u0440\u0430\u043b\u044b \u0430\u049b\u043f\u0430\u0440\u0430\u0442\u0442\u044b \u043a\u04e9\u0440\u0441\u0435\u0442\u0443.", + "PlayNextEpisodeAutomatically": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0431\u04e9\u043b\u0456\u043c\u0434\u0456 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443", + "LabelMaxChromecastBitrate": "Chromecast \u0442\u0430\u0441\u044b\u043c\u0430\u043b\u0434\u0430\u043d\u0443 \u0441\u0430\u043f\u0430\u0441\u044b:", + "LabelSkipBackLength": "\u0410\u0440\u0442\u049b\u0430 \u04e9\u0442\u043a\u0456\u0437\u0456\u043f \u0436\u0456\u0431\u0435\u0440\u0443 \u04b1\u0437\u0430\u049b\u0442\u044b\u0493\u044b:", + "LabelSkipForwardLength": "\u0410\u043b\u0493\u0430 \u04e9\u0442\u043a\u0456\u0437\u0456\u043f \u0436\u0456\u0431\u0435\u0440\u0443 \u04b1\u0437\u0430\u049b\u0442\u044b\u0493\u044b:", + "EnableCinemaMode": "\u041a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440 \u0440\u0435\u0436\u0456\u043c\u0456\u043d \u049b\u043e\u0441\u0443", + "LabelInternetQuality": "\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u0433\u0456 \u0441\u0430\u043f\u0430\u0441\u044b:", + "HeaderMusicQuality": "\u041c\u0443\u0437\u044b\u043a\u0430 \u0441\u0430\u043f\u0430\u0441\u044b", + "LabelHomeNetworkQuality": "\u04ae\u0439\u043b\u0456\u043a \u0436\u0435\u043b\u0456 \u0441\u0430\u043f\u0430\u0441\u044b:", + "HeaderLatestMedia": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440", + "HeaderRestartingEmbyServer": "Emby Server \u049b\u0430\u0439\u0442\u0430 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0443\u0434\u0430", + "RestartPleaseWaitMessage": "Emby Server \u0436\u04b1\u043c\u044b\u0441\u044b \u0430\u044f\u049b\u0442\u0430\u043b\u044b\u043f, \u049b\u0430\u0439\u0442\u0430 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0448\u0430 \u0434\u0435\u0439\u0456\u043d \u043a\u04af\u0442\u0435 \u0442\u04b1\u0440\u044b\u04a3\u044b\u0437. \u0411\u04b1\u043b \u0431\u0456\u0440-\u0435\u043a\u0456 \u043c\u0438\u043d\u04e9\u0442\u049b\u0430 \u0441\u043e\u0437\u044b\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.", + "PlayNext": "\u041a\u0435\u043b\u0435\u0441\u0456\u043d\u0456 \u043e\u0439\u043d\u0430\u0442\u0443", + "AllowSeasonalThemes": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435\u0433\u0456 \u043c\u0430\u0443\u0441\u044b\u043c\u0434\u044b\u049b \u0442\u0430\u049b\u044b\u0440\u044b\u043f\u0442\u0430\u0440\u0493\u0430 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0443", + "AllowSeasonalThemesHelp": "\u049a\u043e\u0441\u044b\u043b\u0493\u0430\u043d \u0431\u043e\u043b\u0441\u0430, \u043c\u0430\u0443\u0441\u044b\u043c\u0434\u044b\u049b \u0442\u0430\u049b\u044b\u0440\u044b\u043f\u0442\u0430\u0440 \u0430\u043d\u0434\u0430-\u0441\u0430\u043d\u0434\u0430 \u0442\u0430\u049b\u044b\u0440\u044b\u043f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456\u04a3\u0456\u0437\u0434\u0456\u04a3 \u043a\u04af\u0448\u0456\u043d \u0436\u043e\u044f\u0434\u044b.", + "AutoBasedOnLanguageSetting": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 (\u0442\u0456\u043b \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456 \u043d\u0435\u0433\u0456\u0437\u0456\u043d\u0434\u0435)", + "LabelDateTimeLocale": "\u041a\u04af\u043d \u043c\u0435\u043d \u0443\u0430\u049b\u044b\u0442:", + "DirectorValue": "\u0420\u0435\u0436\u0438\u0441\u0441\u0435\u0440\u0456: {0}", + "DirectorsValue": "\u0420\u0435\u0436\u0438\u0441\u0441\u0435\u0440\u043b\u0435\u0440; {0}", + "GenreValue": "\u0416\u0430\u043d\u0440: {0}", + "GenresValue": "\u0416\u0430\u043d\u0440\u043b\u0430\u0440: {0}", + "LinksValue": "\u0421\u0456\u043b\u0442\u0435\u043c\u0435\u043b\u0435\u0440: {0}", + "TagsValue": "\u0422\u0435\u0433\u0442\u0435\u0440: {0}", + "LabelAudio": "\u0414\u044b\u0431\u044b\u0441:", + "LabelVideo": "\u0411\u0435\u0439\u043d\u0435:", + "LabelSubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440:", + "Off": "\u04e8\u0448\u0456\u0440", + "ShowTitle": "\u041a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c \u0430\u0442\u0430\u0443\u044b", + "ShowYear": "\u041a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c \u0436\u044b\u043b\u044b", + "Filters": "\u0421\u04af\u0437\u0433\u0456\u043b\u0435\u0440", + "Unplayed": "\u041e\u0439\u043d\u0430\u0442\u044b\u043b\u043c\u0430\u0493\u0430\u043d", + "LabelTVHomeScreen": "\u0422\u0414 \u0440\u0435\u0436\u0456\u043c\u0456\u043d\u0434\u0435\u0433\u0456 \u0431\u0430\u0441\u0442\u044b \u044d\u043a\u0440\u0430\u043d:", + "Horizontal": "\u041a\u04e9\u043b\u0434\u0435\u043d\u0435\u04a3", + "Vertical": "\u0422\u0456\u0433\u0456\u043d\u0435\u043d", + "GroupBySeries": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f\u043b\u0430\u0440 \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0442\u043e\u043f\u0442\u0430\u0441\u0442\u044b\u0440\u0443", + "HeaderVideoType": "\u0411\u0435\u0439\u043d\u0435 \u0442\u04af\u0440\u0456", + "HeaderSeriesStatus": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f \u043a\u04af\u0439\u0456", + "Features": "\u0415\u0440\u0435\u043a\u0448\u0435\u043b\u0456\u043a\u0442\u0435\u0440", + "Trailers": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440", + "Extras": "\u049a\u043e\u0441\u044b\u043c\u0448\u0430\u043b\u0430\u0440", + "ThemeSongs": "\u0422\u0430\u049b\u044b\u0440\u044b\u043f\u0442\u044b\u049b \u04d9\u0443\u0435\u043d\u0434\u0435\u0440", + "ThemeVideos": "\u0422\u0430\u049b\u044b\u0440\u044b\u043f\u0442\u044b\u049b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440", + "HeaderFavoriteMovies": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b \u0444\u0438\u043b\u044c\u043c\u0434\u0435\u0440", + "HeaderFavoriteShows": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c\u0434\u0435\u0440", + "HeaderFavoriteEpisodes": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b \u0431\u04e9\u043b\u0456\u043c\u0434\u0435\u0440", + "HeaderFavoriteVideos": "\u0422\u0430\u043d\u0434\u0430\u0443\u043b\u044b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440", + "HeaderFavoriteGames": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b \u043e\u0439\u044b\u043d\u0434\u0430\u0440", + "HeaderFavoriteArtists": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b \u043e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b\u043b\u0430\u0440", + "HeaderFavoriteAlbums": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b \u0430\u043b\u044c\u0431\u043e\u043c\u0434\u0430\u0440", + "HeaderFavoriteSongs": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b \u04d9\u0443\u0435\u043d\u0434\u0435\u0440", + "Ascending": "\u0410\u0440\u0442\u0443\u044b \u0431\u043e\u0439\u044b\u043d\u0448\u0430", + "Descending": "\u041a\u0435\u043c\u0443\u0456 \u0431\u043e\u0439\u044b\u043d\u0448\u0430", + "ColorPrimaries": "\u0422\u04af\u0441 \u043d\u0435\u0433\u0456\u0437\u0433\u0456\u043b\u0435\u0440\u0456", + "ColorSpace": "\u0422\u04af\u0441 \u043a\u0435\u04a3\u0456\u0441\u0442\u0456\u0433\u0456", + "ColorTransfer": "\u0422\u04af\u0441 \u0430\u0443\u0441\u0442\u044b\u0440\u0443\u044b", + "VideoRange": "\u0411\u0435\u0439\u043d\u0435 \u0430\u0443\u049b\u044b\u043c\u044b", + "SeriesDisplayOrderHelp": "\u0411\u04e9\u043b\u0456\u043c\u0434\u0435\u0440\u0434\u0456 \u044d\u0444\u0438\u0440 \u043a\u04af\u043d\u0456\u043c\u0435\u043d, DVD \u0440\u0435\u0442\u0456\u043c\u0435\u043d \u043d\u0435\u043c\u0435\u0441\u0435 \u0442\u04af\u043f\u043d\u04b1\u0441\u049b\u0430\u043b\u044b\u049b \u043d\u04e9\u043c\u0456\u0440\u043b\u0435\u0443\u0456\u043c\u0435\u043d \u0440\u0435\u0442\u0442\u0435\u0443.", + "PlaybackSettingsIntro": "\u04d8\u0434\u0435\u043f\u043a\u0456 \u043e\u0439\u043d\u0430\u0442\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u0443 \u04af\u0448\u0456\u043d \u0431\u0435\u0439\u043d\u0435 \u043e\u0439\u043d\u0430\u0442\u0443\u0434\u044b \u0442\u043e\u049b\u0442\u0430\u0442\u044b\u04a3\u044b\u0437, \u0441\u043e\u0434\u0430\u043d \u043a\u0435\u0439\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u043d\u044b\u04a3 \u0436\u043e\u0493\u0430\u0440\u0493\u044b \u043e\u04a3 \u0436\u0430\u049b \u0431\u04e9\u043b\u0456\u0433\u0456\u043d\u0434\u0435\u0433\u0456 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0431\u0435\u043b\u0433\u0456\u0448\u0435\u0441\u0456\u043d \u0431\u0430\u0441\u044b\u04a3\u044b\u0437.", + "SubtitleSettingsIntro": "\u04d8\u0434\u0435\u043f\u043a\u0456 \u0441\u0443\u0431\u0442\u0438\u0442\u0440 \u043a\u04e9\u0440\u0456\u043d\u0456\u0441\u0456\u043d \u0436\u04d9\u043d\u0435 \u0442\u0456\u043b \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u0443 \u04af\u0448\u0456\u043d \u0431\u0435\u0439\u043d\u0435 \u043e\u0439\u043d\u0430\u0442\u0443\u0434\u044b \u0442\u043e\u049b\u0442\u0430\u0442\u044b\u04a3\u044b\u0437, \u0441\u043e\u0434\u0430\u043d \u043a\u0435\u0439\u0456\u043d \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u043d\u044b\u04a3 \u0436\u043e\u0493\u0430\u0440\u0493\u044b \u043e\u04a3 \u0436\u0430\u049b \u0431\u04e9\u043b\u0456\u0433\u0456\u043d\u0434\u0435\u0433\u0456 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0431\u0435\u043b\u0433\u0456\u0448\u0435\u0441\u0456\u043d \u0431\u0430\u0441\u044b\u04a3\u044b\u0437." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/ko.json b/src/bower_components/emby-webcomponents/strings/ko.json index 030586a94f..f70b87f20e 100644 --- a/src/bower_components/emby-webcomponents/strings/ko.json +++ b/src/bower_components/emby-webcomponents/strings/ko.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "접근이 제한되었습니다. 다시 시도하세요.", - "Actor": "배우", - "Add": "추가", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "재생목록에 추가", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "모두", - "AllChannels": "모든 채널", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "모든 에피소드", - "AllLanguages": "모든 언어", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "신규", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "배경", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "취소", - "ButtonGotIt": "그럴게요.", - "ButtonOk": "OK", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "다시 시작", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "다시 시도하세요", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "작곡가", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "이 항목을 삭제하면 파일 시스템과 라이브러리 모두에서 삭제됩니다. 계속하겠습니까?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "삭제 확인", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "접속", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "일", - "Default": "Default", - "DefaultErrorMessage": "요구 처리 과정에 오류가 발생하였습니다. 다시 시도하세요.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "삭제", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "감독", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "싫어함", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "다운로드", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "편집", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "자막 편집", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "시네마 모드 사용", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "오류", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "금요일", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "컬렉션에 추가", - "HeaderAddToPlaylist": "재생목록에 추가", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "녹화 취소 확인", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "항목 삭제", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "메타데이터 설정", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "내 미디어 (작음)", - "HeaderNewRecording": "신규 녹화", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "재생 오류", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "날짜 선택", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "스페셜 에피소드 정보", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "도움말", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "이미지", - "ImdbRating": "IMDb rating", - "InstallingPackage": "{0} 설치 중", - "InstantMix": "인스턴트 믹스", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} 항목", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D 형식:", - "LabelAirDays": "방영일:", - "LabelAirTime": "방영 시각:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "앨범", - "LabelAlbumArtists": "앨범 아티스트:", - "LabelArtists": "아티스트:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "생일:", - "LabelBirthYear": "생년:", - "LabelBitrateMbps": "비트레이트 (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "커뮤니티 평점:", - "LabelContentType": "콘텐츠 종류:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "국가:", - "LabelCriticRating": "Critic 평점:", - "LabelCustomRating": "사용자 평점:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "추가한 날짜:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "사망일:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "표시 순서:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "항목 제한:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "언어:", - "LabelLockItemToPreventChanges": "변경할 수 없게 항목 잠금", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "다운로드 선호 언어:", - "LabelName": "Name:", - "LabelNumber": "번호:", - "LabelOriginalAspectRatio": "원 화면비율:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "줄거리:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "등급:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "출생지:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "재생목록:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "프로파일:", - "LabelQuality": "품질:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "개봉일:", - "LabelRuntimeMinutes": "상영 시간 (분):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "줄거리 요약:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "상태:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "동기화 작업 이름:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "동기화 장치:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "태그라인:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "트랙 번호:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "웹사이트:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "더 알아보기", - "Like": "좋아함", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "라이브", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "자동 시리즈 녹화를 예약하려면 Jellyfin 프리미어 가입이 필요합니다.", - "MessageAreYouSureDeleteSubtitles": "이 자막 파일을 삭제하겠습니까?", - "MessageConfirmRecordingCancellation": "이 녹화를 취소하겠습니까?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "항목이 저장되었습니다.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "월요일", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "새 컬렉션", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "항목이 없습니다.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "열기", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "최초 방송일: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} 설치 취소.", - "PackageInstallCompleted": "{0} 설치 완료.", - "PackageInstallFailed": "{0} 설치 실패.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "재생", - "PlayAllFromHere": "여기부터 모두 재생", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "재생함", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "최소 두 개의 항목을 선택하세요.", - "Premiere": "프리미어", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "프로듀서", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "여기부터 모두 대기열에 추가", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "녹화", - "RecordSeries": "시리즈 녹화", - "RecordingCancelled": "녹화가 취소되었습니다.", - "RecordingScheduled": "녹화가 예약되었습니다.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "새로 고침", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "재생목록에서 제거", - "RemovingFromDevice": "Removing from device", - "Repeat": "반복", - "RepeatAll": "모두 반복", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "현재 이미지 교체", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "토요일", - "Save": "저장", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "찾기", - "SearchForCollectionInternetMetadata": "인터넷에서 아트워크와 메타데이터 검색", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "자막 검색", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "시리즈가 취소되었습니다.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "시리즈 녹화가 예약되었습니다.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "설정", - "SettingsSaved": "Settings saved.", - "Share": "공유", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "작음", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "정렬 제목", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "일요일", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "태그", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "목요일", - "TrackCount": "{0} 트랙", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "화요일", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} 앨범", - "ValueDiscNumber": "디스크 {0}", - "ValueEpisodeCount": "{0} 에피소드", - "ValueGameCount": "{0} 게임", - "ValueMinutes": "{0} 분", - "ValueMovieCount": "{0} 영화", - "ValueMusicVideoCount": "{0} 뮤직 비디오", - "ValueOneAlbum": "1 앨범", - "ValueOneEpisode": "1 에피소드", - "ValueOneGame": "1 게임", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 영화", - "ValueOneMusicVideo": "1 뮤직 비디오", - "ValueOneSeries": "1 시리즈", - "ValueOneSong": "1 노래", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} 시리즈", - "ValueSongCount": "{0} 노래", - "ValueSpecialEpisodeName": "특별편 - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "앨범 보기", - "ViewArtist": "아티스트 보기", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "시청함", - "Wednesday": "수요일", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "작가", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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": "\ud2b9\ubcc4\ud3b8 - {0}", + "Share": "\uacf5\uc720", + "Add": "\ucd94\uac00", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "\uc2e0\uaddc", + "Premiere": "\ud504\ub9ac\ubbf8\uc5b4", + "Live": "\ub77c\uc774\ube0c", + "Repeat": "\ubc18\ubcf5", + "TrackCount": "{0} \ud2b8\ub799", + "ItemCount": "{0} \ud56d\ubaa9", + "OriginalAirDateValue": "\ucd5c\ucd08 \ubc29\uc1a1\uc77c: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "\ub0a0\uc9dc \uc120\ud0dd", + "Watched": "\uc2dc\uccad\ud568", + "AirDate": "Air date", + "Played": "\uc7ac\uc0dd\ud568", + "ButtonOk": "OK", + "ButtonCancel": "\ucde8\uc18c", + "AccessRestrictedTryAgainLater": "\uc811\uadfc\uc774 \uc81c\ud55c\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud558\uc138\uc694.", + "ButtonGotIt": "\uadf8\ub7f4\uac8c\uc694.", + "ButtonRestart": "\ub2e4\uc2dc \uc2dc\uc791", + "RecordingCancelled": "\ub179\ud654\uac00 \ucde8\uc18c\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", + "SeriesCancelled": "\uc2dc\ub9ac\uc988\uac00 \ucde8\uc18c\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", + "RecordingScheduled": "\ub179\ud654\uac00 \uc608\uc57d\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", + "SeriesRecordingScheduled": "\uc2dc\ub9ac\uc988 \ub179\ud654\uac00 \uc608\uc57d\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", + "HeaderNewRecording": "\uc2e0\uaddc \ub179\ud654", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "\uc77c\uc694\uc77c", + "Monday": "\uc6d4\uc694\uc77c", + "Tuesday": "\ud654\uc694\uc77c", + "Wednesday": "\uc218\uc694\uc77c", + "Thursday": "\ubaa9\uc694\uc77c", + "Friday": "\uae08\uc694\uc77c", + "Saturday": "\ud1a0\uc694\uc77c", + "Days": "\uc77c", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "\uc2dc\ub9ac\uc988 \ub179\ud654", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "\uc790\ub3d9 \uc2dc\ub9ac\uc988 \ub179\ud654\ub97c \uc608\uc57d\ud558\ub824\uba74 Emby \ud504\ub9ac\ubbf8\uc5b4 \uac00\uc785\uc774 \ud544\uc694\ud569\ub2c8\ub2e4.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "\ub179\ud654", + "Save": "\uc800\uc7a5", + "Edit": "\ud3b8\uc9d1", + "Download": "\ub2e4\uc6b4\ub85c\ub4dc", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "\uc0ad\uc81c", + "HeaderDeleteItem": "\ud56d\ubaa9 \uc0ad\uc81c", + "ConfirmDeleteItem": "\uc774 \ud56d\ubaa9\uc744 \uc0ad\uc81c\ud558\uba74 \ud30c\uc77c \uc2dc\uc2a4\ud15c\uacfc \ub77c\uc774\ube0c\ub7ec\ub9ac \ubaa8\ub450\uc5d0\uc11c \uc0ad\uc81c\ub429\ub2c8\ub2e4. \uacc4\uc18d\ud558\uaca0\uc2b5\ub2c8\uae4c?", + "Refresh": "\uc0c8\ub85c \uace0\uce68", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "\uceec\ub809\uc158\uc5d0 \ucd94\uac00", + "NewCollection": "\uc0c8 \uceec\ub809\uc158", + "LabelCollection": "Collection:", + "Help": "\ub3c4\uc6c0\ub9d0", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "\uc778\ud130\ub137\uc5d0\uc11c \uc544\ud2b8\uc6cc\ud06c\uc640 \uba54\ud0c0\ub370\uc774\ud130 \uac80\uc0c9", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "\uc7ac\uc0dd\ubaa9\ub85d:", + "AddToPlaylist": "\uc7ac\uc0dd\ubaa9\ub85d\uc5d0 \ucd94\uac00", + "HeaderAddToPlaylist": "\uc7ac\uc0dd\ubaa9\ub85d\uc5d0 \ucd94\uac00", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "\uc790\ub9c9 \uac80\uc0c9", + "LabelLanguage": "\uc5b8\uc5b4:", + "Search": "\ucc3e\uae30", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "\uc774 \uc790\ub9c9 \ud30c\uc77c\uc744 \uc0ad\uc81c\ud558\uaca0\uc2b5\ub2c8\uae4c?", + "ConfirmDeletion": "\uc0ad\uc81c \ud655\uc778", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "\uc790\ub9c9 \ud3b8\uc9d1", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "\ud604\uc7ac \uc774\ubbf8\uc9c0 \uad50\uccb4", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "\ud56d\ubaa9\uc774 \uc5c6\uc2b5\ub2c8\ub2e4.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "\ub2e4\uc2dc \uc2dc\ub3c4\ud558\uc138\uc694", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "\ub514\uc2a4\ud06c {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "\uc88b\uc544\ud568", + "Dislike": "\uc2eb\uc5b4\ud568", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "\uc5f4\uae30", + "Play": "\uc7ac\uc0dd", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "\uc778\uc2a4\ud134\ud2b8 \ubbf9\uc2a4", + "ViewAlbum": "\uc568\ubc94 \ubcf4\uae30", + "ViewArtist": "\uc544\ud2f0\uc2a4\ud2b8 \ubcf4\uae30", + "QueueAllFromHere": "\uc5ec\uae30\ubd80\ud130 \ubaa8\ub450 \ub300\uae30\uc5f4\uc5d0 \ucd94\uac00", + "PlayAllFromHere": "\uc5ec\uae30\ubd80\ud130 \ubaa8\ub450 \uc7ac\uc0dd", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "\uc7ac\uc0dd\ubaa9\ub85d\uc5d0\uc11c \uc81c\uac70", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "\ucd5c\uc18c \ub450 \uac1c\uc758 \ud56d\ubaa9\uc744 \uc120\ud0dd\ud558\uc138\uc694.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "\ub179\ud654 \ucde8\uc18c \ud655\uc778", + "MessageConfirmRecordingCancellation": "\uc774 \ub179\ud654\ub97c \ucde8\uc18c\ud558\uaca0\uc2b5\ub2c8\uae4c?", + "Error": "\uc624\ub958", + "VoiceInput": "Voice Input", + "LabelContentType": "\ucf58\ud150\uce20 \uc885\ub958:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "\ucd94\uac00\ud55c \ub0a0\uc9dc:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "\uc0c1\ud0dc:", + "LabelArtists": "\uc544\ud2f0\uc2a4\ud2b8:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "\uc568\ubc94 \uc544\ud2f0\uc2a4\ud2b8:", + "LabelAlbum": "\uc568\ubc94", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "\ucee4\ubba4\ub2c8\ud2f0 \ud3c9\uc810:", + "LabelCriticRating": "Critic \ud3c9\uc810:", + "CriticRating": "Critic rating", + "LabelWebsite": "\uc6f9\uc0ac\uc774\ud2b8:", + "LabelTagline": "\ud0dc\uadf8\ub77c\uc778:", + "LabelOverview": "\uc904\uac70\ub9ac:", + "LabelShortOverview": "\uc904\uac70\ub9ac \uc694\uc57d:", + "LabelReleaseDate": "\uac1c\ubd09\uc77c:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "\ucd9c\uc0dd\uc9c0:", + "Aired": "Aired", + "LabelAirDays": "\ubc29\uc601\uc77c:", + "LabelAirTime": "\ubc29\uc601 \uc2dc\uac01:", + "LabelRuntimeMinutes": "\uc0c1\uc601 \uc2dc\uac04 (\ubd84):", + "LabelParentalRating": "\ub4f1\uae09:", + "LabelCustomRating": "\uc0ac\uc6a9\uc790 \ud3c9\uc810:", + "LabelOriginalAspectRatio": "\uc6d0 \ud654\uba74\ube44\uc728:", + "Label3DFormat": "3D \ud615\uc2dd:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "\uc2a4\ud398\uc15c \uc5d0\ud53c\uc18c\ub4dc \uc815\ubcf4", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "\ud45c\uc2dc \uc21c\uc11c:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "\ud0dc\uadf8", + "HeaderMetadataSettings": "\uba54\ud0c0\ub370\uc774\ud130 \uc124\uc815", + "People": "People", + "LabelMetadataDownloadLanguage": "\ub2e4\uc6b4\ub85c\ub4dc \uc120\ud638 \uc5b8\uc5b4:", + "LabelLockItemToPreventChanges": "\ubcc0\uacbd\ud560 \uc218 \uc5c6\uac8c \ud56d\ubaa9 \uc7a0\uae08", + "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", + "LabelCountry": "\uad6d\uac00:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "\uc0dd\ub144:", + "LabelBirthDate": "\uc0dd\uc77c:", + "LabelDeathDate": "\uc0ac\ub9dd\uc77c:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "\ud2b8\ub799 \ubc88\ud638:", + "LabelNumber": "\ubc88\ud638:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "\uc815\ub82c \uc81c\ubaa9", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "\ubc30\uacbd", + "Images": "\uc774\ubbf8\uc9c0", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "\ubc30\uc6b0", + "Composer": "\uc791\uace1\uac00", + "Director": "\uac10\ub3c5", + "GuestStar": "Guest star", + "Producer": "\ud504\ub85c\ub4c0\uc11c", + "Writer": "\uc791\uac00", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "{0} \uc124\uce58 \uc911", + "PackageInstallCompleted": "{0} \uc124\uce58 \uc644\ub8cc.", + "PackageInstallFailed": "{0} \uc124\uce58 \uc2e4\ud328.", + "PackageInstallCancelled": "{0} \uc124\uce58 \ucde8\uc18c.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 \ub178\ub798", + "ValueSongCount": "{0} \ub178\ub798", + "ValueOneMovie": "1 \uc601\ud654", + "ValueMovieCount": "{0} \uc601\ud654", + "ValueOneSeries": "1 \uc2dc\ub9ac\uc988", + "ValueSeriesCount": "{0} \uc2dc\ub9ac\uc988", + "ValueOneEpisode": "1 \uc5d0\ud53c\uc18c\ub4dc", + "ValueEpisodeCount": "{0} \uc5d0\ud53c\uc18c\ub4dc", + "ValueOneGame": "1 \uac8c\uc784", + "ValueGameCount": "{0} \uac8c\uc784", + "ValueOneAlbum": "1 \uc568\ubc94", + "ValueAlbumCount": "{0} \uc568\ubc94", + "ValueOneMusicVideo": "1 \ubba4\uc9c1 \ube44\ub514\uc624", + "ValueMusicVideoCount": "{0} \ubba4\uc9c1 \ube44\ub514\uc624", + "ValueMinutes": "{0} \ubd84", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "\ud56d\ubaa9\uc774 \uc800\uc7a5\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "\ub3d9\uae30\ud654 \uc791\uc5c5 \uc774\ub984:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "\ud488\uc9c8:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "\ub354 \uc54c\uc544\ubcf4\uae30", + "LabelProfile": "\ud504\ub85c\ud30c\uc77c:", + "LabelBitrateMbps": "\ube44\ud2b8\ub808\uc774\ud2b8 (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "\ud56d\ubaa9 \uc81c\ud55c:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "\uc124\uc815", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "\ubaa8\ub450", + "AllChannels": "\ubaa8\ub4e0 \ucc44\ub110", + "LabelRecord": "Record:", + "NewEpisodesOnly": "New episodes only", + "AllEpisodes": "\ubaa8\ub4e0 \uc5d0\ud53c\uc18c\ub4dc", + "LabelStartWhenPossible": "Start when possible:", + "LabelStopWhenPossible": "Stop when possible:", + "MinutesBefore": "minutes before", + "MinutesAfter": "minutes after", + "SkipEpisodesAlreadyInMyLibrary": "Don't record 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", + "DefaultErrorMessage": "\uc694\uad6c \ucc98\ub9ac \uacfc\uc815\uc5d0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud558\uc600\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud558\uc138\uc694.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "\uc811\uc18d", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "\ub0b4 \ubbf8\ub514\uc5b4 (\uc791\uc74c)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "\ub3d9\uae30\ud654 \uc7a5\uce58:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "\ubaa8\ub4e0 \uc5b8\uc5b4", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "\uc7ac\uc0dd \uc624\ub958", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "\ubaa8\ub450 \ubc18\ubcf5", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "\uc791\uc74c", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "\uc2dc\ub124\ub9c8 \ubaa8\ub4dc \uc0ac\uc6a9", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/lt-lt.json b/src/bower_components/emby-webcomponents/strings/lt-lt.json index 64c5fc8f43..71e77a8625 100644 --- a/src/bower_components/emby-webcomponents/strings/lt-lt.json +++ b/src/bower_components/emby-webcomponents/strings/lt-lt.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Aktorius", - "Add": "Pridėti", - "AddToCollection": "Pridėti į kolekciją", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Pridėti į grojaraštį", - "AddedOnValue": "Added {0}", - "Advanced": "Smulkiau", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "Visi kanalai", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Visas serijas", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Bet kada", - "AroundTime": "Maždaug {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "Kiek tik įmanoma", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "Naujas", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Fonai", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Gimimo vieta", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Atšaukti", - "ButtonGotIt": "Supratau", - "ButtonOk": "OK", - "ButtonPlayOneMinute": "Atkurti vieną minutę", - "ButtonRestart": "Iš naujo", - "ButtonRestorePreviousPurchase": "Atkurti pirkimą", - "ButtonTryAgain": "Bandyti dar", - "ButtonUnlockPrice": "Atrakinti {0}", - "ButtonUnlockWithPurchase": "Atrakinti perkant", - "CancelDownload": "Cancel download", - "CancelRecording": "Atšaukti įrašymą", - "CancelSeries": "Atšaukti laidą", - "Categories": "Kategorijos", - "ChannelNameOnly": "Kanalas tik {0}", - "ChannelNumber": "Kanalo numeris", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Kinoteatro režimas papildomai rodo anonsus ir kitą medžiagą prieš filmą.", - "CloudSyncFeatureDescription": "Sinchronizuokite savo mediją su debesimi lengvam išsaugojimui, archyvavimui ir konvertavimui.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Kompozitorius", - "ConfigureDateAdded": "Pakeisti, kaip nustatoma pridėjimo data galima Jellyfin Serveryje prie Bibliotekos nustatymų", - "ConfirmDeleteImage": "Trinti paveikslą?", - "ConfirmDeleteItem": "Tai atlikus elementas bus ištrintas ir iš bibliotekos, ir iš failų sistemos. Ar tikrai norite tęsti?", - "ConfirmDeleteItems": "Tai atlikus šie elementai bus ištrinti ir iš bibliotekos, ir iš failų sistemos. Ar tikrai norite tęsti?", - "ConfirmDeletion": "Patvirtinti trynimą", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Tęsiamas", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Šalys", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Dienos", - "Default": "Default", - "DefaultErrorMessage": "Įvyko klaida vykdant užklausą. Pabandykite vėliau.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Ištrinti", - "DeleteMedia": "Trinti mediją", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Režisierius", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Nepatinka", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Neįrašyti", - "Down": "Down", - "Download": "Siųstis", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Atsiuntimai", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR reikalauja aktyvios Jellyfin Premiere prenumeratos.", - "Edit": "Redaguoti", - "EditImages": "Redaguoti paveikslus", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Redaguoti subtitrus", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Įjungti spalvotus fonus", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Pasibaigė", - "EndsAtValue": "Baigiasi {0}", - "Episodes": "Episodes", - "Error": "Klaida", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Mėgstamas", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "Šiai funkcijai reikia aktyvios Jellyfin Serverio prenumeratos.", - "Features": "Features", - "File": "Failas", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Gaukite nemokamas Jellyfin programėles savo įrenginiams.", - "Friday": "Penktadienis", - "GenreValue": "Genre: {0}", - "Genres": "Žanrai", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Grupuoti versijas", - "GuestStar": "Kviestinė žvaigždė", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD laidoms", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Pridėti į Kolekciją", - "HeaderAddToPlaylist": "Pridėti į Grojaraštį", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Gauti Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Jellyfin Premiere privalumai", - "HeaderCancelRecording": "Atšaukti įrašą", - "HeaderCancelSeries": "Atšaukti laidą", - "HeaderCinemaMode": "Kinoteatro režimas", - "HeaderCloudSync": "Sinch. su debesimi", - "HeaderConfirmRecordingCancellation": "Patvirtinti įrašo atšaukimą", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Konvertuokite savo įrašus", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Ištrinti elementą", - "HeaderDeleteItems": "Ištrinti elementus", - "HeaderDisplaySettings": "Rodymo nustatymai", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Redaguoti paveikslus", - "HeaderEnabledFields": "Įjungti laukeliai", - "HeaderEnabledFieldsHelp": "Nuimkite varnelę nuo lauko kad jį užrakinti ir neleisti keisti jo duomenų.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Nemokamos Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Įveskite vieną ar daugiau paieškos kriterijų. Pašalinkite kriterijų jei norite gauti daugiau paieškos rezultatų.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Palikti įrašą", - "HeaderKeepSeries": "Palikti laidą", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Sužinoti daugiau", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metaduomenų nustatymai", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "Naujas įrašas", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Vietinė medija", - "HeaderOfflineDownloadsDescription": "Atsisiųsti mediją į savo įrenginius lengvai prieigai be interneto.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Atkurti mano mediją", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Įrašymo nustatymai", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Pasakykite maždaug...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Pasirinkite datą", - "HeaderSeriesOptions": "Laidų nustatymai", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Ypatingos serijos info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Bandomasis atkūrimas", - "HeaderUnlockFeature": "Atrakinti funkciją", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "Jūs pasakėte:", - "Help": "Padėti", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "Kaip sumokėjote?", - "IHaveJellyfinPremiere": "Turiu Jellyfin Premiere", - "IPurchasedThisApp": "Pirkau šią programėlę", - "Identify": "Identifikuoti", - "Images": "Paveiksliukai", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Įdiegiu {0}", - "InstantMix": "Leisti miksą", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} elementų", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Vaikams", - "Label3DFormat": "3D formatas:", - "LabelAirDays": "Eterio dienos:", - "LabelAirTime": "Eterio laikas:", - "LabelAirsAfterSeason": "Rodoma po sezono:", - "LabelAirsBeforeEpisode": "Rodoma prieš seriją:", - "LabelAirsBeforeSeason": "Rodoma prieš sezoną:", - "LabelAlbum": "Albumas:", - "LabelAlbumArtists": "Albumo atlikėjai:", - "LabelArtists": "Atlikėjai:", - "LabelArtistsHelp": "Atskirti kelis naudojant:", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Gimimo data:", - "LabelBirthYear": "Gimimo metai:", - "LabelBitrateMbps": "Kokybė (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Kanalai:", - "LabelCollection": "Kolekcija:", - "LabelCommunityRating": "Bendruomenės vertinimas:", - "LabelContentType": "Turinio tipas:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Šalis:", - "LabelCriticRating": "Kritikų vertinimas:", - "LabelCustomRating": "Kitoks vertinimas:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Pridėjimo data:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Mirties data:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Rodymo tvarka:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} ID:", - "LabelEmailAddress": "E-pašto adresas:", - "LabelEndDate": "Pabaigos data:", - "LabelEpisodeNumber": "Serijos numeris:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Elementų limitas:", - "LabelKeep:": "Laikyti:", - "LabelKeepUpTo": "Spėti iki:", - "LabelLanguage": "Kalba:", - "LabelLockItemToPreventChanges": "Uždrausti šio elemento pakeitimus", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Pageidaujama siuntimo kalba:", - "LabelName": "Pavadinimas:", - "LabelNumber": "Numeris:", - "LabelOriginalAspectRatio": "Originalus formatas:", - "LabelOriginalTitle": "Originalus pavadinimas:", - "LabelOverview": "Apžvalga:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Tėvų reitingas:", - "LabelPath": "Kelias:", - "LabelPersonRole": "Vaidmuo:", - "LabelPersonRoleHelp": "Pavyzdys: Ledų mašinos vairuotojas", - "LabelPlaceOfBirth": "Gimimo vieta:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Grojaraštis:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profilis:", - "LabelQuality": "Kokybė:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Įrašyti:", - "LabelRefreshMode": "Atnaujinimo režimas:", - "LabelReleaseDate": "Išleidimo data:", - "LabelRuntimeMinutes": "Trukmė (min.):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Sezono numeris:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Trumpa apžvalga:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Rūšiavimo pavadinimas:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Jei galima, pradėti:", - "LabelStatus": "Būklė:", - "LabelStopWhenPossible": "Jei galima, nutraukti:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sinchronizavimo darbo pavadinimas:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sinchronizuoti į:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Šūkis:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Pavadinimas:", - "LabelTrackNumber": "Dainos numeris:", - "LabelType": "Tipas:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Tinklapis:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Metai:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Sužinoti daugiau", - "Like": "Patinka", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Tiesiogiai", - "LiveBroadcasts": "Tiesioginėms transliacijoms", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Žymėti rodytu", - "MarkUnplayed": "Žymėti nerodytu", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Norint kurti automatinius laidos įrašus reikia aktyvios Jellyfin Premiere prenumeratos.", - "MessageAreYouSureDeleteSubtitles": "Ar tikrai norite ištrinti šį subtitrų failą?", - "MessageConfirmRecordingCancellation": "Ar tikrai norite atšaukti šį įrašą?", - "MessageDownloadQueued": "Siuntimas užsakytas.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "Jei neleidote programėlei naudoti mikrofono, pakeiskite nustatymus ir bandykite dar kartą.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Elementas išsaugotas.", - "MessageItemsAdded": "Elementai pridėti.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Palikite tuščią kad paveldėtų nustatymus nuo tėviško elemento arba globalias standartines reikšmes.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "Jei turite aktyvią Jellyfin Premiere prenumeratą, sutvarkykite Jellyfin Premiere savo Jellyfin Serverio skydelyje. Tai galite atlikti paspaudė Jellyfin Premiere užrašą pagrindiniame meniu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Atrakinkite šią funkciją nedideliu vienkartiniu mokesčiu arba įsigiję Jellyfin Premiere prenumeratą.", - "MessageUnlockAppWithSupporter": "Atrakinkite šią funkciją įsigiję Jellyfin Premiere prenumeratą.", - "MessageWeDidntRecognizeCommand": "Deja, nepažinome šios komandos.", - "MinutesAfter": "min. po", - "MinutesBefore": "min. prieš", - "Mobile": "Mobile / Tablet", - "Monday": "Pirmadienis", - "More": "More", - "MoveLeft": "Perkelti kairėn", - "MoveRight": "Perkelti dešinėn", - "Movies": "Filmai", - "MySubtitles": "Mano subtitrai", - "Name": "Vardas", - "NewCollection": "Nauja kolekcija", - "NewCollectionHelp": "Kolekcijos leidžia grupuoti filmus ir kitą bibliotekos turinį.", - "NewCollectionNameExample": "Pavyzdys: Star Wars kolekcija", - "NewEpisodes": "Naujoms serijoms", - "NewEpisodesOnly": "Tik naujas serijas", - "News": "Naujienos", - "Next": "Next", - "No": "No", - "NoItemsFound": "Nieko nerasta.", - "NoSubtitleSearchResultsFound": "Nieko neradau.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Atidaryti", - "OptionNew": "Naujas...", - "Original": "Original", - "OriginalAirDateValue": "Pirmo eterio data: {0}", - "Overview": "Apžvalga", - "PackageInstallCancelled": "{0} įdiegimas atšauktas.", - "PackageInstallCompleted": "{0} įdiegimas baigtas.", - "PackageInstallFailed": "{0} įdiegimas nepavyko.", - "ParentalRating": "Tėvų reitingas", - "People": "Žmonės", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Mėgstamiausius kanalus į pradžią", - "Play": "Leisti", - "PlayAllFromHere": "Leisti viską nuo čia", - "PlayCount": "Play count", - "PlayFromBeginning": "Leisti nuo pradžių", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Įveskite vardą arba išorinį ID.", - "PleaseRestartServerName": "Prašau paleisti Jellyfin Serverį iš naujo - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Pasirinkite bent du elementus.", - "Premiere": "Premiera", - "Premieres": "Premieras", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Prodiuseris", - "ProductionLocations": "Filmavimo vietos", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Su Jellyfin Premiere automatiškai paverčia įrašus į transliavimui patogius formatus. Įrašai bus iš karto konvertuojami į MP4 arba MKV priklausomai nuo nustatymų.", - "Quality": "Quality", - "QueueAllFromHere": "Į eilę viską nuo čia", - "Raised": "Raised", - "RecentlyWatched": "Nesenai žiūrėta", - "Record": "Įrašyti", - "RecordSeries": "Įrašyti laidą", - "RecordingCancelled": "Įrašas atšauktas.", - "RecordingScheduled": "Įrašas numatytas.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Atnaujinti", - "RefreshDialogHelp": "Metaduomenys atnaujinami pagal Jellyfin Serverio nustatymus ir įjungtas interneto paslaugas.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Atnaujinimas užsakytas.", - "Reject": "Reject", - "ReleaseDate": "Išleidimo data", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Pašalinti iš kolekcijos", - "RemoveFromPlaylist": "Pašalinti iš grojaraščio", - "RemovingFromDevice": "Removing from device", - "Repeat": "Kartojimas", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Kartojamoms serijoms", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Pakeisti visus metaduomenis", - "ReplaceExistingImages": "Pakeisti esamus paveikslus", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Tęsti nuo {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Trukmė", - "Saturday": "Šeštadienis", - "Save": "Saugoti", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Ekrano nuotraukos", - "Search": "Ieškoti", - "SearchForCollectionInternetMetadata": "Ieškoti internete iliustracijų ir metaduomenų", - "SearchForMissingMetadata": "Ieškoti trūkstamų metaduomenų", - "SearchForSubtitles": "Ieškoti subtitrų", - "SearchResults": "Paieškos rezultatai", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Laida atšaukta.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Laidos įrašas numatytas.", - "SeriesSettings": "Laidų nustatymai", - "SeriesYearToPresent": "{0} - dabar", - "ServerNameIsRestarting": "Jellyfin Serveris - {0} leidžiamas iš naujo.", - "ServerNameIsShuttingDown": "Jellyfin Serveris - {0} išsijungia.", - "ServerUpdateNeeded": "Šį Jellyfin serverį reikia atnaujinti. Naujausią versiją atsisiųsti galite {0}", - "Settings": "Nustatymai", - "SettingsSaved": "Settings saved.", - "Share": "Dalintis", - "ShowIndicatorsFor": "Rodyti indikatorius:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Atsitiktinai", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Kai įmanoma serijos bus lyginamos pagal sezonų ir serijų skaičius.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Rūšiuoti kanalus pagal:", - "SortName": "Rūšiavimo vardas", - "Sports": "Sportas", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studijos", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitrai", - "Suggestions": "Suggestions", - "Sunday": "Sekmadienis", - "Sync": "Sinchronizuoti", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Žymės", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Išbandykite vieną minutę atkūrimo. Ačiū kad bandote Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Ketvirtadienis", - "TrackCount": "{0} dainų", - "Trailer": "Anonsas", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Pabandykite Multi-Select", - "TryMultiSelectMessage": "Kelių elementų redagavimui paspauskite ir palaikykite ant bet kurio plakato, o tada pasirinkite norimus redaguoti elementus. Pabandykite!", - "Tuesday": "Antradienis", - "Uniform": "Uniform", - "UnlockGuide": "Atrakinti gidą", - "Unplayed": "Unplayed", - "Unrated": "Nevertinta", - "UntilIDelete": "Kol ištrinsiu", - "UntilSpaceNeeded": "Kol pritrūks vietos", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albumų", - "ValueDiscNumber": "Diskas {0}", - "ValueEpisodeCount": "{0} serijų", - "ValueGameCount": "{0} žaidimų", - "ValueMinutes": "{0} min.", - "ValueMovieCount": "{0} filmų", - "ValueMusicVideoCount": "{0} muzikiniai video", - "ValueOneAlbum": "1 albumas", - "ValueOneEpisode": "1 serija", - "ValueOneGame": "1 žaidimas", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 filmas", - "ValueOneMusicVideo": "1 muzikinis video", - "ValueOneSeries": "1 laida", - "ValueOneSong": "1 daina", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} laidų", - "ValueSongCount": "{0} dainų", - "ValueSpecialEpisodeName": "Ypatinga - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "Žiūrėti albumą", - "ViewArtist": "Žiūrėti atlikėją", - "VoiceInput": "Balso komandos", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Trečiadienis", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Rašytojas", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "Atrakinkite \u0161i\u0105 funkcij\u0105 nedideliu vienkartiniu mokes\u010diu arba \u012fsigij\u0119 Emby Premiere prenumerat\u0105.", + "MessageUnlockAppWithSupporter": "Atrakinkite \u0161i\u0105 funkcij\u0105 \u012fsigij\u0119 Emby Premiere prenumerat\u0105.", + "MessageToValidateSupporter": "Jei turite aktyvi\u0105 Emby Premiere prenumerat\u0105, sutvarkykite Emby Premiere savo Emby Serverio skydelyje. Tai galite atlikti paspaud\u0117 Emby Premiere u\u017era\u0161\u0105 pagrindiniame meniu.", + "ValueSpecialEpisodeName": "Ypatinga - {0}", + "Share": "Dalintis", + "Add": "Prid\u0117ti", + "ServerUpdateNeeded": "\u0160\u012f Emby server\u012f reikia atnaujinti. Naujausi\u0105 versij\u0105 atsisi\u0173sti galite {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "Naujas", + "Premiere": "Premiera", + "Live": "Tiesiogiai", + "Repeat": "Kartojimas", + "TrackCount": "{0} dain\u0173", + "ItemCount": "{0} element\u0173", + "OriginalAirDateValue": "Pirmo eterio data: {0}", + "EndsAtValue": "Baigiasi {0}", + "HeaderSelectDate": "Pasirinkite dat\u0105", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "OK", + "ButtonCancel": "At\u0161aukti", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Supratau", + "ButtonRestart": "I\u0161 naujo", + "RecordingCancelled": "\u012era\u0161as at\u0161auktas.", + "SeriesCancelled": "Laida at\u0161aukta.", + "RecordingScheduled": "\u012era\u0161as numatytas.", + "SeriesRecordingScheduled": "Laidos \u012fra\u0161as numatytas.", + "HeaderNewRecording": "Naujas \u012fra\u0161as", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Sekmadienis", + "Monday": "Pirmadienis", + "Tuesday": "Antradienis", + "Wednesday": "Tre\u010diadienis", + "Thursday": "Ketvirtadienis", + "Friday": "Penktadienis", + "Saturday": "\u0160e\u0161tadienis", + "Days": "Dienos", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "\u012era\u0161yti laid\u0105", + "HeaderCinemaMode": "Kinoteatro re\u017eimas", + "HeaderCloudSync": "Sinch. su debesimi", + "Downloads": "Atsiuntimai", + "HeaderMyDownloads": "My Downloads", + "HeaderOfflineDownloads": "Vietin\u0117 medija", + "HeaderOfflineDownloadsDescription": "Atsisi\u0173sti medij\u0105 \u012f savo \u012frenginius lengvai prieigai be interneto.", + "CloudSyncFeatureDescription": "Sinchronizuokite savo medij\u0105 su debesimi lengvam i\u0161saugojimui, archyvavimui ir konvertavimui.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "CinemaModeFeatureDescription": "Kinoteatro re\u017eimas papildomai rodo anonsus ir kit\u0105 med\u017eiag\u0105 prie\u0161 film\u0105.", + "HeaderFreeApps": "Nemokamos Emby Apps", + "FreeAppsFeatureDescription": "Gaukite nemokamas Emby program\u0117les savo \u012frenginiams.", + "HeaderBecomeProjectSupporter": "Gauti Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Norint kurti automatinius laidos \u012fra\u0161us reikia aktyvios Emby Premiere prenumeratos.", + "LabelEmailAddress": "E-pa\u0161to adresas:", + "PromoConvertRecordingsToStreamingFormat": "Su Emby Premiere automati\u0161kai paver\u010dia \u012fra\u0161us \u012f transliavimui patogius formatus. \u012era\u0161ai bus i\u0161 karto konvertuojami \u012f MP4 arba MKV priklausomai nuo nustatym\u0173.", + "FeatureRequiresEmbyPremiere": "\u0160iai funkcijai reikia aktyvios Emby Serverio prenumeratos.", + "HeaderConvertYourRecordings": "Konvertuokite savo \u012fra\u0161us", + "Record": "\u012era\u0161yti", + "Save": "Saugoti", + "Edit": "Redaguoti", + "Download": "Si\u0173stis", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Smulkiau", + "Delete": "I\u0161trinti", + "HeaderDeleteItem": "I\u0161trinti element\u0105", + "ConfirmDeleteItem": "Tai atlikus elementas bus i\u0161trintas ir i\u0161 bibliotekos, ir i\u0161 fail\u0173 sistemos. Ar tikrai norite t\u0119sti?", + "Refresh": "Atnaujinti", + "RefreshQueued": "Atnaujinimas u\u017esakytas.", + "AddToCollection": "Prid\u0117ti \u012f kolekcij\u0105", + "HeaderAddToCollection": "Prid\u0117ti \u012f Kolekcij\u0105", + "NewCollection": "Nauja kolekcija", + "LabelCollection": "Kolekcija:", + "Help": "Pad\u0117ti", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Kolekcijos leid\u017eia grupuoti filmus ir kit\u0105 bibliotekos turin\u012f.", + "SearchForCollectionInternetMetadata": "Ie\u0161koti internete iliustracij\u0173 ir metaduomen\u0173", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Pavadinimas:", + "NewCollectionNameExample": "Pavyzdys: Star Wars kolekcija", + "MessageItemsAdded": "Elementai prid\u0117ti.", + "OptionNew": "Naujas...", + "LabelPlaylist": "Grojara\u0161tis:", + "AddToPlaylist": "Prid\u0117ti \u012f grojara\u0161t\u012f", + "HeaderAddToPlaylist": "Prid\u0117ti \u012f Grojara\u0161t\u012f", + "Subtitles": "Subtitrai", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Ie\u0161koti subtitr\u0173", + "LabelLanguage": "Kalba:", + "Search": "Ie\u0161koti", + "NoSubtitleSearchResultsFound": "Nieko neradau.", + "File": "Failas", + "MessageAreYouSureDeleteSubtitles": "Ar tikrai norite i\u0161trinti \u0161\u012f subtitr\u0173 fail\u0105?", + "ConfirmDeletion": "Patvirtinti trynim\u0105", + "MySubtitles": "Mano subtitrai", + "MessageDownloadQueued": "Siuntimas u\u017esakytas.", + "EditSubtitles": "Redaguoti subtitrus", + "UnlockGuide": "Atrakinti gid\u0105", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Pakeisti esamus paveikslus", + "ReplaceAllMetadata": "Pakeisti visus metaduomenis", + "SearchForMissingMetadata": "Ie\u0161koti tr\u016bkstam\u0173 metaduomen\u0173", + "LabelRefreshMode": "Atnaujinimo re\u017eimas:", + "NoItemsFound": "Nieko nerasta.", + "HeaderSaySomethingLike": "Pasakykite ma\u017edaug...", + "ButtonTryAgain": "Bandyti dar", + "HeaderYouSaid": "J\u016bs pasak\u0117te:", + "MessageWeDidntRecognizeCommand": "Deja, nepa\u017einome \u0161ios komandos.", + "MessageIfYouBlockedVoice": "Jei neleidote program\u0117lei naudoti mikrofono, pakeiskite nustatymus ir bandykite dar kart\u0105.", + "ValueDiscNumber": "Diskas {0}", + "Unrated": "Nevertinta", + "Favorite": "M\u0117gstamas", + "Like": "Patinka", + "Dislike": "Nepatinka", + "RefreshDialogHelp": "Metaduomenys atnaujinami pagal Emby Serverio nustatymus ir \u012fjungtas interneto paslaugas.", + "Open": "Atidaryti", + "Play": "Leisti", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Atsitiktinai", + "Identify": "Identifikuoti", + "EditImages": "Redaguoti paveikslus", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sinchronizuoti", + "InstantMix": "Leisti miks\u0105", + "ViewAlbum": "\u017di\u016br\u0117ti album\u0105", + "ViewArtist": "\u017di\u016br\u0117ti atlik\u0117j\u0105", + "QueueAllFromHere": "\u012e eil\u0119 visk\u0105 nuo \u010dia", + "PlayAllFromHere": "Leisti visk\u0105 nuo \u010dia", + "PlayFromBeginning": "Leisti nuo prad\u017ei\u0173", + "ResumeAt": "T\u0119sti nuo {0}", + "RemoveFromPlaylist": "Pa\u0161alinti i\u0161 grojara\u0161\u010dio", + "RemoveFromCollection": "Pa\u0161alinti i\u0161 kolekcijos", + "Sort": "Sort", + "Trailer": "Anonsas", + "MarkPlayed": "\u017dym\u0117ti rodytu", + "MarkUnplayed": "\u017dym\u0117ti nerodytu", + "GroupVersions": "Grupuoti versijas", + "PleaseSelectTwoItems": "Pasirinkite bent du elementus.", + "TryMultiSelect": "Pabandykite Multi-Select", + "TryMultiSelectMessage": "Keli\u0173 element\u0173 redagavimui paspauskite ir palaikykite ant bet kurio plakato, o tada pasirinkite norimus redaguoti elementus. Pabandykite!", + "HeaderConfirmRecordingCancellation": "Patvirtinti \u012fra\u0161o at\u0161aukim\u0105", + "MessageConfirmRecordingCancellation": "Ar tikrai norite at\u0161aukti \u0161\u012f \u012fra\u0161\u0105?", + "Error": "Klaida", + "VoiceInput": "Balso komandos", + "LabelContentType": "Turinio tipas:", + "LabelPath": "Kelias:", + "Playlists": "Playlists", + "LabelTitle": "Pavadinimas:", + "LabelOriginalTitle": "Originalus pavadinimas:", + "LabelSortTitle": "R\u016b\u0161iavimo pavadinimas:", + "LabelDateAdded": "Prid\u0117jimo data:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Pakeisti, kaip nustatoma prid\u0117jimo data galima Emby Serveryje prie Bibliotekos nustatym\u0173", + "LabelStatus": "B\u016bkl\u0117:", + "LabelArtists": "Atlik\u0117jai:", + "LabelArtistsHelp": "Atskirti kelis naudojant:", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Albumo atlik\u0117jai:", + "LabelAlbum": "Albumas:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Bendruomen\u0117s vertinimas:", + "LabelCriticRating": "Kritik\u0173 vertinimas:", + "CriticRating": "Critic rating", + "LabelWebsite": "Tinklapis:", + "LabelTagline": "\u0160\u016bkis:", + "LabelOverview": "Ap\u017evalga:", + "LabelShortOverview": "Trumpa ap\u017evalga:", + "LabelReleaseDate": "I\u0161leidimo data:", + "LabelYear": "Metai:", + "LabelPlaceOfBirth": "Gimimo vieta:", + "Aired": "Aired", + "LabelAirDays": "Eterio dienos:", + "LabelAirTime": "Eterio laikas:", + "LabelRuntimeMinutes": "Trukm\u0117 (min.):", + "LabelParentalRating": "T\u0117v\u0173 reitingas:", + "LabelCustomRating": "Kitoks vertinimas:", + "LabelOriginalAspectRatio": "Originalus formatas:", + "Label3DFormat": "3D formatas:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Ypatingos serijos info", + "LabelAirsBeforeSeason": "Rodoma prie\u0161 sezon\u0105:", + "LabelAirsAfterSeason": "Rodoma po sezono:", + "LabelAirsBeforeEpisode": "Rodoma prie\u0161 serij\u0105:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Rodymo nustatymai", + "LabelDisplayOrder": "Rodymo tvarka:", + "Display": "Display", + "Countries": "\u0160alys", + "Genres": "\u017danrai", + "Studios": "Studijos", + "Tags": "\u017dym\u0117s", + "HeaderMetadataSettings": "Metaduomen\u0173 nustatymai", + "People": "\u017dmon\u0117s", + "LabelMetadataDownloadLanguage": "Pageidaujama siuntimo kalba:", + "LabelLockItemToPreventChanges": "U\u017edrausti \u0161io elemento pakeitimus", + "MessageLeaveEmptyToInherit": "Palikite tu\u0161\u010di\u0105 kad paveld\u0117t\u0173 nustatymus nuo t\u0117vi\u0161ko elemento arba globalias standartines reik\u0161mes.", + "LabelCountry": "\u0160alis:", + "LabelDynamicExternalId": "{0} ID:", + "LabelBirthYear": "Gimimo metai:", + "LabelBirthDate": "Gimimo data:", + "LabelDeathDate": "Mirties data:", + "LabelEndDate": "Pabaigos data:", + "LabelSeasonNumber": "Sezono numeris:", + "LabelEpisodeNumber": "Serijos numeris:", + "LabelTrackNumber": "Dainos numeris:", + "LabelNumber": "Numeris:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "R\u016b\u0161iavimo vardas", + "ReleaseDate": "I\u0161leidimo data", + "Continuing": "T\u0119siamas", + "Ended": "Pasibaig\u0117", + "HeaderEnabledFields": "\u012ejungti laukeliai", + "HeaderEnabledFieldsHelp": "Nuimkite varnel\u0119 nuo lauko kad j\u012f u\u017erakinti ir neleisti keisti jo duomen\u0173.", + "Backdrops": "Fonai", + "Images": "Paveiksliukai", + "Runtime": "Trukm\u0117", + "ProductionLocations": "Filmavimo vietos", + "BirthLocation": "Gimimo vieta", + "ParentalRating": "T\u0117v\u0173 reitingas", + "PlayCount": "Play count", + "Name": "Vardas", + "Overview": "Ap\u017evalga", + "LabelType": "Tipas:", + "LabelPersonRole": "Vaidmuo:", + "LabelPersonRoleHelp": "Pavyzdys: Led\u0173 ma\u0161inos vairuotojas", + "Actor": "Aktorius", + "Composer": "Kompozitorius", + "Director": "Re\u017eisierius", + "GuestStar": "Kviestin\u0117 \u017evaig\u017ed\u0117", + "Producer": "Prodiuseris", + "Writer": "Ra\u0161ytojas", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "\u012ediegiu {0}", + "PackageInstallCompleted": "{0} \u012fdiegimas baigtas.", + "PackageInstallFailed": "{0} \u012fdiegimas nepavyko.", + "PackageInstallCancelled": "{0} \u012fdiegimas at\u0161auktas.", + "SeriesYearToPresent": "{0} - dabar", + "ValueOneItem": "1 item", + "ValueOneSong": "1 daina", + "ValueSongCount": "{0} dain\u0173", + "ValueOneMovie": "1 filmas", + "ValueMovieCount": "{0} film\u0173", + "ValueOneSeries": "1 laida", + "ValueSeriesCount": "{0} laid\u0173", + "ValueOneEpisode": "1 serija", + "ValueEpisodeCount": "{0} serij\u0173", + "ValueOneGame": "1 \u017eaidimas", + "ValueGameCount": "{0} \u017eaidim\u0173", + "ValueOneAlbum": "1 albumas", + "ValueAlbumCount": "{0} album\u0173", + "ValueOneMusicVideo": "1 muzikinis video", + "ValueMusicVideoCount": "{0} muzikiniai video", + "ValueMinutes": "{0} min.", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "\u012eveskite vien\u0105 ar daugiau paie\u0161kos kriterij\u0173. Pa\u0161alinkite kriterij\u0173 jei norite gauti daugiau paie\u0161kos rezultat\u0173.", + "PleaseEnterNameOrId": "\u012eveskite vard\u0105 arba i\u0161orin\u012f ID.", + "MessageItemSaved": "Elementas i\u0161saugotas.", + "SearchResults": "Paie\u0161kos rezultatai", + "ServerNameIsRestarting": "Emby Serveris - {0} leid\u017eiamas i\u0161 naujo.", + "ServerNameIsShuttingDown": "Emby Serveris - {0} i\u0161sijungia.", + "HeaderDeleteItems": "I\u0161trinti elementus", + "ConfirmDeleteItems": "Tai atlikus \u0161ie elementai bus i\u0161trinti ir i\u0161 bibliotekos, ir i\u0161 fail\u0173 sistemos. Ar tikrai norite t\u0119sti?", + "PleaseRestartServerName": "Pra\u0161au paleisti Emby Server\u012f i\u0161 naujo - {0}.", + "LabelSyncJobName": "Sinchronizavimo darbo pavadinimas:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Kokyb\u0117:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Su\u017einoti daugiau", + "LabelProfile": "Profilis:", + "LabelBitrateMbps": "Kokyb\u0117 (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Element\u0173 limitas:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Ekrano nuotraukos", + "MoveRight": "Perkelti de\u0161in\u0117n", + "MoveLeft": "Perkelti kair\u0117n", + "ConfirmDeleteImage": "Trinti paveiksl\u0105?", + "HeaderEditImages": "Redaguoti paveikslus", + "Settings": "Nustatymai", + "ShowIndicatorsFor": "Rodyti indikatorius:", + "NewEpisodes": "Naujoms serijoms", + "Episodes": "Episodes", + "HDPrograms": "HD laidoms", + "Programs": "Programs", + "LiveBroadcasts": "Tiesiogin\u0117ms transliacijoms", + "Premieres": "Premieras", + "RepeatEpisodes": "Kartojamoms serijoms", + "DvrSubscriptionRequired": "Emby DVR reikalauja aktyvios Emby Premiere prenumeratos.", + "HeaderCancelRecording": "At\u0161aukti \u012fra\u0161\u0105", + "CancelRecording": "At\u0161aukti \u012fra\u0161ym\u0105", + "HeaderKeepRecording": "Palikti \u012fra\u0161\u0105", + "HeaderCancelSeries": "At\u0161aukti laid\u0105", + "HeaderKeepSeries": "Palikti laid\u0105", + "HeaderLearnMore": "Su\u017einoti daugiau", + "DeleteMedia": "Trinti medij\u0105", + "SeriesSettings": "Laid\u0173 nustatymai", + "HeaderRecordingOptions": "\u012era\u0161ymo nustatymai", + "CancelSeries": "At\u0161aukti laid\u0105", + "DoNotRecord": "Ne\u012fra\u0161yti", + "HeaderSeriesOptions": "Laid\u0173 nustatymai", + "LabelChannels": "Kanalai:", + "ChannelNameOnly": "Kanalas tik {0}", + "Anytime": "Bet kada", + "AnyLanguage": "Any language", + "AroundTime": "Ma\u017edaug {0}", + "All": "All", + "AllChannels": "Visi kanalai", + "LabelRecord": "\u012era\u0161yti:", + "NewEpisodesOnly": "Tik naujas serijas", + "AllEpisodes": "Visas serijas", + "LabelStartWhenPossible": "Jei galima, prad\u0117ti:", + "LabelStopWhenPossible": "Jei galima, nutraukti:", + "MinutesBefore": "min. prie\u0161", + "MinutesAfter": "min. po", + "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", + "SkipEpisodesAlreadyInMyLibraryHelp": "Kai \u012fmanoma serijos bus lyginamos pagal sezon\u0173 ir serij\u0173 skai\u010dius.", + "LabelKeepUpTo": "Sp\u0117ti iki:", + "AsManyAsPossible": "Kiek tik \u012fmanoma", + "DefaultErrorMessage": "\u012evyko klaida vykdant u\u017eklaus\u0105. Pabandykite v\u0117liau.", + "LabelKeep:": "Laikyti:", + "UntilIDelete": "Kol i\u0161trinsiu", + "UntilSpaceNeeded": "Kol pritr\u016bks vietos", + "Categories": "Kategorijos", + "Sports": "Sportas", + "News": "Naujienos", + "Movies": "Filmai", + "Kids": "Vaikams", + "EnableColorCodedBackgrounds": "\u012ejungti spalvotus fonus", + "SortChannelsBy": "R\u016b\u0161iuoti kanalus pagal:", + "RecentlyWatched": "Nesenai \u017ei\u016br\u0117ta", + "ChannelNumber": "Kanalo numeris", + "HeaderBenefitsEmbyPremiere": "Emby Premiere privalumai", + "ThankYouForTryingEnjoyOneMinute": "I\u0161bandykite vien\u0105 minut\u0119 atk\u016brimo. A\u010di\u016b kad bandote Emby.", + "HeaderTryPlayback": "Bandomasis atk\u016brimas", + "HowDidYouPay": "Kaip sumok\u0117jote?", + "IHaveEmbyPremiere": "Turiu Emby Premiere", + "IPurchasedThisApp": "Pirkau \u0161i\u0105 program\u0117l\u0119", + "ButtonRestorePreviousPurchase": "Atkurti pirkim\u0105", + "ButtonUnlockWithPurchase": "Atrakinti perkant", + "ButtonUnlockPrice": "Atrakinti {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}", + "HeaderAlreadyPaid": "Already Paid?", + "ButtonPlayOneMinute": "Atkurti vien\u0105 minut\u0119", + "PlaceFavoriteChannelsAtBeginning": "M\u0117gstamiausius kanalus \u012f prad\u017ei\u0105", + "HeaderUnlockFeature": "Atrakinti funkcij\u0105", + "MessageDidYouKnowCinemaMode": "Ar \u017einote, kad su Emby Premiere gausite daugiau funkcij\u0173, toki\u0173 kaip Kinoteatro re\u017eimas?", + "MessageDidYouKnowCinemaMode2": "Kinoteatro re\u017eimas papildomai rodo anonsus ir kit\u0105 med\u017eiag\u0105 prie\u0161 film\u0105.", + "HeaderPlayMyMedia": "Atkurti mano medij\u0105", + "HeaderDiscoverEmbyPremiere": "Atrasti Emby Premiere", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sinchronizuoti \u012f:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/ms.json b/src/bower_components/emby-webcomponents/strings/ms.json index 94b5242f8d..9c69093afb 100644 --- a/src/bower_components/emby-webcomponents/strings/ms.json +++ b/src/bower_components/emby-webcomponents/strings/ms.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Cancel", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friday", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Country:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Language:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Monday", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Saturday", - "Save": "Save", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Sunday", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Thursday", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tuesday", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Wednesday", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Cancel", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Save", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Language:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Country:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/nb.json b/src/bower_components/emby-webcomponents/strings/nb.json index a80683775b..bf6c1dff6f 100644 --- a/src/bower_components/emby-webcomponents/strings/nb.json +++ b/src/bower_components/emby-webcomponents/strings/nb.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolutt", - "Accept": "Aksepter", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Skuespiller", - "Add": "Legg til", - "AddToCollection": "Legg til i samling", - "AddToPlayQueue": "Legg til i spilleliste", - "AddToPlaylist": "Legg til spilleliste", - "AddedOnValue": "Lagt til {0}", - "Advanced": "Avansert", - "AirDate": "Air date", - "Aired": "Sendt tidligere", - "Albums": "Album", - "All": "All", - "AllChannels": "Alle kanaler", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Alle episoder", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "For å gjenopprette tidligere kjøp, må du forsikre deg om at du er logget på enheten med samme Google- (eller Amazonkonto) som opprinnelig gjorde kjøpet. Pass på at appbutikken er aktivert og ikke begrenset av foreldrekontroll,samt sørg for at du har en aktiv internettforbindelse. Du må bare gjøre dette en gang for å gjenopprette ditt tidligere kjøp.", - "AnyLanguage": "Any language", - "Anytime": "Enhver tid", - "AroundTime": "Rundt {0}", - "Art": "Art", - "Artists": "Artister", - "AsManyAsPossible": "Så mange som mulig", - "Ascending": "Ascending", - "AspectRatio": "Størrelsesforholdet", - "AttemptingWakeServer": "Prøver å vekke opp server. Vennligst vent,..", - "AttributeNew": "Ny", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Automatisk", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Passer best", - "BirthLocation": "Fødelesested", - "Books": "Bøker", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Avbryt", - "ButtonGotIt": "Skjønner", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Spill av et minutt", - "ButtonRestart": "Omstart", - "ButtonRestorePreviousPurchase": "Gjenopprett kjøp", - "ButtonTryAgain": "Prøv igjen", - "ButtonUnlockPrice": "Lås opp {0}", - "ButtonUnlockWithPurchase": "Lås opp ved kjøp", - "CancelDownload": "Avbryt nedlasting", - "CancelRecording": "Avbryt opptak", - "CancelSeries": "Avbryt serie", - "Categories": "Kategorier", - "ChannelNameOnly": "Kun kanal {0}", - "ChannelNumber": "Kanal nummer", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Kinomodus gir deg den ekte kinoopplevelsen med trailere og tilpassede introer før funksjonen.", - "CloudSyncFeatureDescription": "Synkroniser mediene til skyen for sikkerhetskopiering, arkivering og konvertering.", - "Collections": "Samlinger", - "ColorPrimaries": "Primærfarger", - "ColorSpace": "Fargeutvalg", - "ColorTransfer": "Overføring av farger", - "CommunityRating": "Community rating", - "Composer": "Komponist", - "ConfigureDateAdded": "Konfigurer hvordan dato er fastsatt i Jellyfin Server sitt dashbord under Bibliotek innstillinger", - "ConfirmDeleteImage": "Slett bilde?", - "ConfirmDeleteItem": "Sletting av elementet vil slette det fra både filsystemet og biblioteket. Er du sikker på at du vil fortsette?", - "ConfirmDeleteItems": "Sletting av disse elementene vil slette dem fra både filsystemet og mediebiblioteket . Er du sikker på at du vil fortsette?", - "ConfirmDeletion": "Bekreft Kansellering", - "ConfirmEndPlayerSession": "Vill du stenge Jellyfin på denne enheten?", - "ConfirmRemoveDownload": "Fjern nedlastet?", - "Connect": "Koble til", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Forsett", - "ContinueInSecondsValue": "Forsett om {0} sekunder", - "ContinueWatching": "Fortsett å se på", - "Continuing": "Fortsetter", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Land", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Dager", - "Default": "Default", - "DefaultErrorMessage": "Det skjedde en feil under behandling av forespørselen. Vennligst prøv igjen senere.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Slett", - "DeleteMedia": "Slett elementet", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Regissør", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Koble fra", - "Dislike": "Misliker", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Ikke ta opp", - "Down": "Ned", - "Download": "Nedlasting", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Nedlastet", - "Downloading": "Laster ned", - "DownloadingDots": "Downloading...", - "Downloads": "Nedlastinger", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Planlegg enkelt Live opptak, serieopptak og mer med Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR krever et aktivt Jellyfin Premiere-abonnement.", - "Edit": "Rediger", - "EditImages": "Endre bilder", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Endre undertekster", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Aktiver kino mode", - "EnableColorCodedBackgrounds": "Aktiver fargekoder for bakgrunn", - "EnableDisplayMirroring": "Aktivert skjermspeiling", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Avsluttet", - "EndsAtValue": "Slutter klokken {0}", - "Episodes": "Episoder", - "Error": "Feil", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favoritt", - "Favorites": "Favoritter", - "FeatureRequiresJellyfinPremiere": "Denne funksjonen krever et aktivt Jellyfin Premiere abonnement.", - "Features": "Features", - "File": "Fil", - "Fill": "Fyll ut", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Nyt gratis tilgang til Jellyfin Applikasjoner på din enhet", - "Friday": "Fredag", - "GenreValue": "Genre: {0}", - "Genres": "Sjanger", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Gjeste skuespiller", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD Programmer", - "HeaderActiveRecordings": "Aktive opptak", - "HeaderAddToCollection": "Legg til samling", - "HeaderAddToPlaylist": "Legg til Spilleliste", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Allerede betalt?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Lydbøker", - "HeaderAudioSettings": "Lyd inntilligner", - "HeaderBecomeProjectSupporter": "Skaff Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Fordeler med Jellyfin Premiere", - "HeaderCancelRecording": "Avbryt opptak", - "HeaderCancelSeries": "Avbryt serie", - "HeaderCinemaMode": "Kinomodus", - "HeaderCloudSync": "Sky-synkronisering", - "HeaderConfirmRecordingCancellation": "Bekreft Avbryt Opptak", - "HeaderContinueListening": "Forsett og høre på", - "HeaderContinueWatching": "Forsett og se på", - "HeaderConvertYourRecordings": "Konverter dine opptak", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Slett element", - "HeaderDeleteItems": "Slett elementer", - "HeaderDisplaySettings": "Skjerminnstillinger", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Endre bilder", - "HeaderEnabledFields": "Aktiverte felt", - "HeaderEnabledFieldsHelp": "Fjern merket et felt for å låse den og hindre sine data blir endret.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorittspillelister", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Gratis Jellyfin Applikasjoner", - "HeaderHomeScreen": "Hjemskjerm", - "HeaderIdentifyItemHelp": "Oppgi ett eller flere søke kriterier. Fjern kriterie for å øke søke resultater.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Behold opptak", - "HeaderKeepSeries": "Behold serie", - "HeaderLatestChannelItems": "Siste kanal elementer", - "HeaderLatestChannelMedia": "Siste kanalelementer", - "HeaderLatestFrom": "Siste fra {0}", - "HeaderLatestMedia": "Nyeste media", - "HeaderLatestRecordings": "Siste opptak", - "HeaderLearnMore": "Lær mere", - "HeaderLibraryFolders": "Bibliotek mapper", - "HeaderLibraryOrder": "Bibliotekenes rekkefølge", - "HeaderMetadataSettings": "Metadata innstilinger", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "Min enhet", - "HeaderMyDownloads": "Mine nedlastinger", - "HeaderMyMedia": "Min Media", - "HeaderMyMediaSmall": "Min Media (liten)", - "HeaderNewRecording": "Nye opptak:", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Neste", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Nedlastede media", - "HeaderOfflineDownloadsDescription": "Last ned media til din enhet for enkel offline bruk", - "HeaderOnNow": "På Nå", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Spill min media", - "HeaderPlayOn": "Forsett avspilling", - "HeaderPlaybackError": "Avspillingsfeil", - "HeaderRecordingOptions": "Opptak innstillinger", - "HeaderRemoteControl": "Fjernkontroll", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Si noenting slik som...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Velg dato", - "HeaderSeriesOptions": "Serie innstillinger", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Spesial Episode info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Undertekster innstillinger", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Kjøps betingelser", - "HeaderTryPlayback": "Prøv tilbakespilling", - "HeaderUnlockFeature": "Lås opp funksjon", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Vekk opp server", - "HeaderYouSaid": "Du sa...", - "Help": "Hjelp", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Skjul sett innhold fra nyeste media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "Hvordan betalte du?", - "IHaveJellyfinPremiere": "Jeg har Jellyfin Premiere", - "IPurchasedThisApp": "Jeg har kjøpt denne appen", - "Identify": "Identifiser", - "Images": "Bilder", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installerer {0}", - "InstantMix": "Direktemiks", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} elementer", - "Items": "Elementer", - "KeepDownload": "Behold nedlasting", - "KeepOnDevice": "Behold på enhet", - "Kids": "Barn", - "Label3DFormat": "3D format:", - "LabelAirDays": "Sendings dager:", - "LabelAirTime": "Sendings tid:", - "LabelAirsAfterSeason": "Sendt etter sesong:", - "LabelAirsBeforeEpisode": "Sendt før episode:", - "LabelAirsBeforeSeason": "Send før sesong:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artister:", - "LabelArtists": "Artister:", - "LabelArtistsHelp": "Skill flere med semikolon ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Fødselsdato:", - "LabelBirthYear": "Fødselsår:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Kanal", - "LabelCollection": "Samling:", - "LabelCommunityRating": "Fellesskap anmeldelse:", - "LabelContentType": "Innholdstype:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Land:", - "LabelCriticRating": "Kritiker anmeldelse:", - "LabelCustomRating": "Kunde anmeldelse:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Dato lagt til:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Dødsdato:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Oversettelse av Jellyfin pågår.", - "LabelDisplayMode": "Visningsmodus:", - "LabelDisplayOrder": "Visningsrekkefølge:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-postadresse:", - "LabelEndDate": "Slutt dato:", - "LabelEpisodeNumber": "Episode nummer:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Hjemskjerm seksjon {0}", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Begrenset antall:", - "LabelKeep:": "Behold", - "LabelKeepUpTo": "Hold opptil", - "LabelLanguage": "Språk:", - "LabelLockItemToPreventChanges": "Lås dette elementet for å hindre fremtidige endringer", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Foretrukket nedlastingsspråk:", - "LabelName": "Navn", - "LabelNumber": "Nummer:", - "LabelOriginalAspectRatio": "Originalt sideforhold:", - "LabelOriginalTitle": "Original tittel:", - "LabelOverview": "Oversikt:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Foreldresensur:", - "LabelPath": "Sti:", - "LabelPersonRole": "Rolle:", - "LabelPersonRoleHelp": "Eksempel: Is bil fører", - "LabelPlaceOfBirth": "Fødested:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Spilleliste", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profil:", - "LabelQuality": "Kvalitet:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Opptak:", - "LabelRefreshMode": "Oppdatering modus:", - "LabelReleaseDate": "Utgivelsesdato:", - "LabelRuntimeMinutes": "Spilletid (minutter):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Sesong nummer:", - "LabelSelectFolderGroups": "Gruppér innhold automatisk etter følgende grupper til visninger som filmer, musikk og TV:", - "LabelSelectFolderGroupsHelp": "Mapper som ikke er merket vil kun bli vist i sin egen visning.", - "LabelShortOverview": "Kort oversikt:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Forkortet tittel:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start når mulig:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop når mulig:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Navn på synkroniseringsjobb:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Synkroniser til:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Slagord:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Tittel:", - "LabelTrackNumber": "Spor nummer:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Nettsted:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Siste {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Lære mer", - "Like": "Liker", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Direkte", - "LiveBroadcasts": "Direkte sending", - "LiveTV": "Direkte TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV krever et aktivt Jellyfin Premium-abonnement.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Merker som sett", - "MarkUnplayed": "Merker som usett", - "MarkWatched": "Marker som sett", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Et aktivt Jellyfin Premiere abonnement er påkrevd for å kunne automatisere serieopptak.", - "MessageAreYouSureDeleteSubtitles": "Er du sikker på at du vil slette denne undertekst filen?", - "MessageConfirmRecordingCancellation": "Er du sikker på at du vil avbryte dette opptaket?", - "MessageDownloadQueued": "Nedlasting satt til i kø", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "Hvis du nektet tale tilgang til applikasjonen må du rekonfigurere før du prøver igjen.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Element lagret.", - "MessageItemsAdded": "Elementer lagt til.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "La være blank for å arve innstillinger fra et foreldre element, eller den globale standard verdien.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "Ingen servere tilgjengelig for å koble til. Hvis du har blitt invitert til å dele en server, må du akseptere den nedenfor eller ved å klikke på lenken i e-posten.", - "MessageNoSyncJobsFound": "Ingen nedlastinger funnet. Opprett nedlastingsjobber ved hjelp av Lastn ed knappene som finnes i hele appen.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Avspilling av dette innholdet er for tiden begrenset. Ta kontakt med Jellyfin Server-administratoren for mer informasjon.", - "MessageToValidateSupporter": "Hvis du har et aktivt Jellyfin Premiere-abonnement, må du sørge for at du har konfigurert Jellyfin Premiere i Jellyfin Server Dashboard, som du får tilgang til ved å klikke Jellyfin Premiere i hovedmenyen.", - "MessageUnlockAppWithPurchaseOrSupporter": "Lås opp denne funksjonen med et engangskjøp, eller med et aktivt Jellyfin Premiere-abonnement.", - "MessageUnlockAppWithSupporter": "Lås opp denne funksjonen med et aktivt Jellyfin Premiere-abonnement.", - "MessageWeDidntRecognizeCommand": "Vi beklager, Vi kunne ikke forstå denne kommandoen.", - "MinutesAfter": "Minutter etter", - "MinutesBefore": "Minutter før", - "Mobile": "Mobile / Tablet", - "Monday": "Mandag", - "More": "Mere", - "MoveLeft": "Flytt venstre", - "MoveRight": "Flytt høyere", - "Movies": "Filmer", - "MySubtitles": "Mine undertekster", - "Name": "Navn", - "NewCollection": "Ny Samling", - "NewCollectionHelp": "Samlinger tillate deg å lage personlige grupperinger av filmer og annet bibliotek innhold.", - "NewCollectionNameExample": "Eksempel: Star Wars-samling", - "NewEpisodes": "Nye episoder", - "NewEpisodesOnly": "Kun nye episoder", - "News": "Nyheter", - "Next": "Next", - "No": "Nei", - "NoItemsFound": "Ingen elementer funnet", - "NoSubtitleSearchResultsFound": "Ingen resulterer funnet.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "Ingen", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "En kanal", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Åpne", - "OptionNew": "Ny...", - "Original": "Original", - "OriginalAirDateValue": "Original utgivelsedato: {0}", - "Overview": "Oversikt", - "PackageInstallCancelled": "{0} installasjon avbrutt.", - "PackageInstallCompleted": "{0} installering fullført.", - "PackageInstallFailed": "{0} installasjon feilet.", - "ParentalRating": "Parental Rating", - "People": "Mennesker", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Plasser favorittkanaler i starten", - "Play": "Spill", - "PlayAllFromHere": "Spill alt herfra", - "PlayCount": "Play count", - "PlayFromBeginning": "Start fra starten", - "PlayNext": "Spill av neste", - "PlayNextEpisodeAutomatically": "Spill av neste episode automatisk", - "PlaybackErrorNoCompatibleStream": "Ingen kompatible strømmer er tilgjengelige for øyeblikket. Prøv igjen senere eller kontakt systemadministratoren for detaljer.", - "PlaybackErrorNotAllowed": "Du er for øyeblikket ikke autorisert til avspilling dette innholdet. Ta kontakt med systemadministratoren for detaljer.", - "PlaybackErrorPlaceHolder": "Sett inn disken for å spille av denne filmen.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Spilt", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Vennligst skriv ett navn eller en ekstern id.", - "PleaseRestartServerName": "Vennligst start gjør en omstart av Jellyfin Server - {0}", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Vennligst velg minst to elementer.", - "Premiere": "Premiere", - "Premieres": "Premierer", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Personvern regler", - "Producer": "Produsent", - "ProductionLocations": "Produksjon lokasjoner", - "Programs": "Programmer", - "PromoConvertRecordingsToStreamingFormat": "Konverter opptak automatisk til et streaming-vennlig format med Jellyfin Premiere. Opptakene konverteres på rappen til MP4 eller MKV, basert på dine Jellyfin-serverinnstillinger.", - "Quality": "Kvalitet", - "QueueAllFromHere": "Kø alt herfra", - "Raised": "Raised", - "RecentlyWatched": "Nylig sett", - "Record": "Ta opp", - "RecordSeries": "Ta opp serien", - "RecordingCancelled": "Opptak er avbrutt.", - "RecordingScheduled": "Opptak planlagt.", - "Recordings": "Opptak", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Oppdater", - "RefreshDialogHelp": "Metadata er oppdatert basert på innstillinger og internett-tjenester som er aktivert i Jellyfin Server dashbordet", - "RefreshMetadata": "Frisk opp metadata", - "RefreshQueued": "Oppdatering kø", - "Reject": "Avstå", - "ReleaseDate": "Utgivelsesdato", - "RemoveDownload": "Fjern nedlastet", - "RemoveFromCollection": "Fjern fra samling", - "RemoveFromPlaylist": "Fjern fra spilleliste", - "RemovingFromDevice": "Fjerner fra enheten", - "Repeat": "Gjenta", - "RepeatAll": "Repetering alle", - "RepeatEpisodes": "Gjenta episode", - "RepeatMode": "Repetering modus", - "RepeatOne": "Repetering en", - "ReplaceAllMetadata": "Erstatt all metadata", - "ReplaceExistingImages": "Bytt ut eksisterende bilder", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Forsett fra {0}", - "Retry": "Prøv igjen", - "RunAtStartup": "Run at startup", - "Runtime": "Spilletid", - "Saturday": "Lørdag", - "Save": "Lagre", - "ScanForNewAndUpdatedFiles": "Se etter nye og oppdaterte filer", - "Schedule": "Planlegg", - "Screenshot": "Screenshot", - "Screenshots": "Skjermbilder", - "Search": "Søk", - "SearchForCollectionInternetMetadata": "Søk på internet for artwork og metadata", - "SearchForMissingMetadata": "Søk etter manglende metadata", - "SearchForSubtitles": "Søk etter undertekster", - "SearchResults": "Søkeresultater", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Serie avbrutt.", - "SeriesDisplayOrderHelp": "Sorter episoder etter sendt dato, DVD-rekkefølge eller nummerering.", - "SeriesRecordingScheduled": "Serieopptak planlagt.", - "SeriesSettings": "Serie innstillinger", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} starter om.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} avsluttes.", - "ServerUpdateNeeded": "Denne Jellyfin serveren må oppdateres. For å laste ned siste versjonen, vennligst besøk: {0}", - "Settings": "Innstillinger", - "SettingsSaved": "Innstillinger lagret", - "Share": "Del", - "ShowIndicatorsFor": "Vis indikatorer for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Programmer", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Ikke ta opp episoder som allerede finnes i biblioteket mitt", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episoder vil bli sammenlignet med sesong- og episode nummer når de er tilgjengelige.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Sanger", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sorter kanaler etter", - "SortName": "Sorterings navn", - "Sports": "Sport", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studioer", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Undertekster", - "Suggestions": "Forslag", - "Sunday": "Søndag", - "Sync": "Synk", - "SyncJobItemStatusCancelled": "Kansellert", - "SyncJobItemStatusConverting": "Konverter", - "SyncJobItemStatusFailed": "Feil", - "SyncJobItemStatusQueued": "Kø", - "SyncJobItemStatusReadyToTransfer": "Klar til overføring", - "SyncJobItemStatusRemovedFromDevice": "Fjernet fra enhet", - "SyncJobItemStatusSynced": "Ned lastet", - "SyncJobItemStatusSyncedMarkForRemoval": "Fjern fra enhet", - "SyncJobItemStatusTransferring": "Overfører", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tagger", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Bruks betingelser", - "ThankYouForTryingEnjoyOneMinute": "Vennligst nyt ett minutt av avspilling. Takk for at du prøver Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Torsdag", - "TrackCount": "{0} spor", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Prøv flervalg", - "TryMultiSelectMessage": "Hvis du vil redigere flere medier elementer, klikker du bare og hold en plakat og velg elementene du ønsker å administrere. Prøv det!", - "Tuesday": "Tirsdag", - "Uniform": "Uniform", - "UnlockGuide": "Lås opp Guide", - "Unplayed": "Unplayed", - "Unrated": "Uvurdert", - "UntilIDelete": "Inntil jeg sletter", - "UntilSpaceNeeded": "Inntil lagringsplass er nødvendig", - "Up": "Opp", - "Upload": "Upload", - "ValueAlbumCount": "{0} album", - "ValueDiscNumber": "Disk {0}", - "ValueEpisodeCount": "{0} episoder", - "ValueGameCount": "{0} spill", - "ValueMinutes": "{0} minutter", - "ValueMovieCount": "{0} filmer", - "ValueMusicVideoCount": "{0} musikkvideoer", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 spill", - "ValueOneItem": "et element", - "ValueOneMovie": "1 film", - "ValueOneMusicVideo": "1 musikkvideo", - "ValueOneSeries": "1 serie", - "ValueOneSong": "1 sang", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} serier", - "ValueSongCount": "{0} sanger", - "ValueSpecialEpisodeName": "Spesial - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Videoområde", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "Vis album", - "ViewArtist": "Vis artist", - "VoiceInput": "Stemme input", - "WakeServer": "Vekk opp server", - "WakeServerError": "Wake On LAN-pakker ble sendt til servermaskinen din, men tilkobling til din Jellyfin Server mislyktes. Serveren din kan trenge litt mer tid til å våkne, eller så kjører ikke Jellyfin Server på maskinen.", - "WakeServerSuccess": "Suksess!", - "Watched": "Sett", - "Wednesday": "Onsdag", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Manus", - "Yes": "Ja" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "L\u00e5s opp denne funksjonen med et engangskj\u00f8p, eller med et aktivt Emby Premiere-abonnement.", + "MessageUnlockAppWithSupporter": "L\u00e5s opp denne funksjonen med et aktivt Emby Premiere-abonnement.", + "MessageToValidateSupporter": "Hvis du har et aktivt Emby Premiere-abonnement, m\u00e5 du s\u00f8rge for at du har konfigurert Emby Premiere i Emby Server Dashboard, som du f\u00e5r tilgang til ved \u00e5 klikke Emby Premiere i hovedmenyen.", + "ValueSpecialEpisodeName": "Spesial - {0}", + "Share": "Del", + "Add": "Legg til", + "ServerUpdateNeeded": "Denne Emby serveren m\u00e5 oppdateres. For \u00e5 laste ned siste versjonen, vennligst bes\u00f8k: {0}", + "LiveTvRequiresUnlock": "Live TV krever et aktivt Emby Premium-abonnement.", + "AttributeNew": "Ny", + "Premiere": "Premiere", + "Live": "Direkte", + "Repeat": "Gjenta", + "TrackCount": "{0} spor", + "ItemCount": "{0} elementer", + "OriginalAirDateValue": "Original utgivelsedato: {0}", + "EndsAtValue": "Slutter klokken {0}", + "HeaderSelectDate": "Velg dato", + "Watched": "Sett", + "AirDate": "Air date", + "Played": "Spilt", + "ButtonOk": "Ok", + "ButtonCancel": "Avbryt", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Skj\u00f8nner", + "ButtonRestart": "Omstart", + "RecordingCancelled": "Opptak er avbrutt.", + "SeriesCancelled": "Serie avbrutt.", + "RecordingScheduled": "Opptak planlagt.", + "SeriesRecordingScheduled": "Serieopptak planlagt.", + "HeaderNewRecording": "Nye opptak:", + "WakeServer": "Vekk opp server", + "HeaderWakeServer": "Vekk opp server", + "AttemptingWakeServer": "Pr\u00f8ver \u00e5 vekke opp server. Vennligst vent,..", + "WakeServerSuccess": "Suksess!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN-pakker ble sendt til servermaskinen din, men tilkobling til din Emby Server mislyktes. Serveren din kan trenge litt mer tid til \u00e5 v\u00e5kne, eller s\u00e5 kj\u00f8rer ikke Emby Server p\u00e5 maskinen.", + "Sunday": "S\u00f8ndag", + "Monday": "Mandag", + "Tuesday": "Tirsdag", + "Wednesday": "Onsdag", + "Thursday": "Torsdag", + "Friday": "Fredag", + "Saturday": "L\u00f8rdag", + "Days": "Dager", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Ta opp serien", + "HeaderCinemaMode": "Kinomodus", + "HeaderCloudSync": "Sky-synkronisering", + "Downloads": "Nedlastinger", + "HeaderMyDownloads": "Mine nedlastinger", + "HeaderOfflineDownloads": "Nedlastede media", + "HeaderOfflineDownloadsDescription": "Last ned media til din enhet for enkel offline bruk", + "CloudSyncFeatureDescription": "Synkroniser mediene til skyen for sikkerhetskopiering, arkivering og konvertering.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Planlegg enkelt Live opptak, serieopptak og mer med Emby DVR.", + "CinemaModeFeatureDescription": "Kinomodus gir deg den ekte kinoopplevelsen med trailere og tilpassede introer f\u00f8r funksjonen.", + "HeaderFreeApps": "Gratis Emby Applikasjoner", + "FreeAppsFeatureDescription": "Nyt gratis tilgang til Emby Applikasjoner p\u00e5 din enhet", + "HeaderBecomeProjectSupporter": "Skaff Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Et aktivt Emby Premiere abonnement er p\u00e5krevd for \u00e5 kunne automatisere serieopptak.", + "LabelEmailAddress": "E-postadresse:", + "PromoConvertRecordingsToStreamingFormat": "Konverter opptak automatisk til et streaming-vennlig format med Emby Premiere. Opptakene konverteres p\u00e5 rappen til MP4 eller MKV, basert p\u00e5 dine Emby-serverinnstillinger.", + "FeatureRequiresEmbyPremiere": "Denne funksjonen krever et aktivt Emby Premiere abonnement.", + "HeaderConvertYourRecordings": "Konverter dine opptak", + "Record": "Ta opp", + "Save": "Lagre", + "Edit": "Rediger", + "Download": "Nedlasting", + "Downloaded": "Nedlastet", + "Downloading": "Laster ned", + "Advanced": "Avansert", + "Delete": "Slett", + "HeaderDeleteItem": "Slett element", + "ConfirmDeleteItem": "Sletting av elementet vil slette det fra b\u00e5de filsystemet og biblioteket. Er du sikker p\u00e5 at du vil fortsette?", + "Refresh": "Oppdater", + "RefreshQueued": "Oppdatering k\u00f8", + "AddToCollection": "Legg til i samling", + "HeaderAddToCollection": "Legg til samling", + "NewCollection": "Ny Samling", + "LabelCollection": "Samling:", + "Help": "Hjelp", + "LabelDisplayMode": "Visningsmodus:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Oversettelse av Emby p\u00e5g\u00e5r.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Samlinger tillate deg \u00e5 lage personlige grupperinger av filmer og annet bibliotek innhold.", + "SearchForCollectionInternetMetadata": "S\u00f8k p\u00e5 internet for artwork og metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Navn", + "NewCollectionNameExample": "Eksempel: Star Wars-samling", + "MessageItemsAdded": "Elementer lagt til.", + "OptionNew": "Ny...", + "LabelPlaylist": "Spilleliste", + "AddToPlaylist": "Legg til spilleliste", + "HeaderAddToPlaylist": "Legg til Spilleliste", + "Subtitles": "Undertekster", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "S\u00f8k etter undertekster", + "LabelLanguage": "Spr\u00e5k:", + "Search": "S\u00f8k", + "NoSubtitleSearchResultsFound": "Ingen resulterer funnet.", + "File": "Fil", + "MessageAreYouSureDeleteSubtitles": "Er du sikker p\u00e5 at du vil slette denne undertekst filen?", + "ConfirmDeletion": "Bekreft Kansellering", + "MySubtitles": "Mine undertekster", + "MessageDownloadQueued": "Nedlasting satt til i k\u00f8", + "EditSubtitles": "Endre undertekster", + "UnlockGuide": "L\u00e5s opp Guide", + "RefreshMetadata": "Frisk opp metadata", + "ReplaceExistingImages": "Bytt ut eksisterende bilder", + "ReplaceAllMetadata": "Erstatt all metadata", + "SearchForMissingMetadata": "S\u00f8k etter manglende metadata", + "LabelRefreshMode": "Oppdatering modus:", + "NoItemsFound": "Ingen elementer funnet", + "HeaderSaySomethingLike": "Si noenting slik som...", + "ButtonTryAgain": "Pr\u00f8v igjen", + "HeaderYouSaid": "Du sa...", + "MessageWeDidntRecognizeCommand": "Vi beklager, Vi kunne ikke forst\u00e5 denne kommandoen.", + "MessageIfYouBlockedVoice": "Hvis du nektet tale tilgang til applikasjonen m\u00e5 du rekonfigurere f\u00f8r du pr\u00f8ver igjen.", + "ValueDiscNumber": "Disk {0}", + "Unrated": "Uvurdert", + "Favorite": "Favoritt", + "Like": "Liker", + "Dislike": "Misliker", + "RefreshDialogHelp": "Metadata er oppdatert basert p\u00e5 innstillinger og internett-tjenester som er aktivert i Emby Server dashbordet", + "Open": "\u00c5pne", + "Play": "Spill", + "AddToPlayQueue": "Legg til i spilleliste", + "Shuffle": "Shuffle", + "Identify": "Identifiser", + "EditImages": "Endre bilder", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Synk", + "InstantMix": "Direktemiks", + "ViewAlbum": "Vis album", + "ViewArtist": "Vis artist", + "QueueAllFromHere": "K\u00f8 alt herfra", + "PlayAllFromHere": "Spill alt herfra", + "PlayFromBeginning": "Start fra starten", + "ResumeAt": "Forsett fra {0}", + "RemoveFromPlaylist": "Fjern fra spilleliste", + "RemoveFromCollection": "Fjern fra samling", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Merker som sett", + "MarkUnplayed": "Merker som usett", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Vennligst velg minst to elementer.", + "TryMultiSelect": "Pr\u00f8v flervalg", + "TryMultiSelectMessage": "Hvis du vil redigere flere medier elementer, klikker du bare og hold en plakat og velg elementene du \u00f8nsker \u00e5 administrere. Pr\u00f8v det!", + "HeaderConfirmRecordingCancellation": "Bekreft Avbryt Opptak", + "MessageConfirmRecordingCancellation": "Er du sikker p\u00e5 at du vil avbryte dette opptaket?", + "Error": "Feil", + "VoiceInput": "Stemme input", + "LabelContentType": "Innholdstype:", + "LabelPath": "Sti:", + "Playlists": "Playlists", + "LabelTitle": "Tittel:", + "LabelOriginalTitle": "Original tittel:", + "LabelSortTitle": "Forkortet tittel:", + "LabelDateAdded": "Dato lagt til:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Konfigurer hvordan dato er fastsatt i Emby Server sitt dashbord under Bibliotek innstillinger", + "LabelStatus": "Status:", + "LabelArtists": "Artister:", + "LabelArtistsHelp": "Skill flere med semikolon ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artister:", + "LabelAlbum": "Album:", + "Artists": "Artister", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Fellesskap anmeldelse:", + "LabelCriticRating": "Kritiker anmeldelse:", + "CriticRating": "Critic rating", + "LabelWebsite": "Nettsted:", + "LabelTagline": "Slagord:", + "LabelOverview": "Oversikt:", + "LabelShortOverview": "Kort oversikt:", + "LabelReleaseDate": "Utgivelsesdato:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "F\u00f8dested:", + "Aired": "Sendt tidligere", + "LabelAirDays": "Sendings dager:", + "LabelAirTime": "Sendings tid:", + "LabelRuntimeMinutes": "Spilletid (minutter):", + "LabelParentalRating": "Foreldresensur:", + "LabelCustomRating": "Kunde anmeldelse:", + "LabelOriginalAspectRatio": "Originalt sideforhold:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Spesial Episode info", + "LabelAirsBeforeSeason": "Send f\u00f8r sesong:", + "LabelAirsAfterSeason": "Sendt etter sesong:", + "LabelAirsBeforeEpisode": "Sendt f\u00f8r episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Skjerminnstillinger", + "LabelDisplayOrder": "Visningsrekkef\u00f8lge:", + "Display": "Display", + "Countries": "Land", + "Genres": "Sjanger", + "Studios": "Studioer", + "Tags": "Tagger", + "HeaderMetadataSettings": "Metadata innstilinger", + "People": "Mennesker", + "LabelMetadataDownloadLanguage": "Foretrukket nedlastingsspr\u00e5k:", + "LabelLockItemToPreventChanges": "L\u00e5s dette elementet for \u00e5 hindre fremtidige endringer", + "MessageLeaveEmptyToInherit": "La v\u00e6re blank for \u00e5 arve innstillinger fra et foreldre element, eller den globale standard verdien.", + "LabelCountry": "Land:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "F\u00f8dsels\u00e5r:", + "LabelBirthDate": "F\u00f8dselsdato:", + "LabelDeathDate": "D\u00f8dsdato:", + "LabelEndDate": "Slutt dato:", + "LabelSeasonNumber": "Sesong nummer:", + "LabelEpisodeNumber": "Episode nummer:", + "LabelTrackNumber": "Spor nummer:", + "LabelNumber": "Nummer:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sorterings navn", + "ReleaseDate": "Utgivelsesdato", + "Continuing": "Fortsetter", + "Ended": "Avsluttet", + "HeaderEnabledFields": "Aktiverte felt", + "HeaderEnabledFieldsHelp": "Fjern merket et felt for \u00e5 l\u00e5se den og hindre sine data blir endret.", + "Backdrops": "Backdrops", + "Images": "Bilder", + "Runtime": "Spilletid", + "ProductionLocations": "Produksjon lokasjoner", + "BirthLocation": "F\u00f8delesested", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Navn", + "Overview": "Oversikt", + "LabelType": "Type:", + "LabelPersonRole": "Rolle:", + "LabelPersonRoleHelp": "Eksempel: Is bil f\u00f8rer", + "Actor": "Skuespiller", + "Composer": "Komponist", + "Director": "Regiss\u00f8r", + "GuestStar": "Gjeste skuespiller", + "Producer": "Produsent", + "Writer": "Manus", + "MessageNoSyncJobsFound": "Ingen nedlastinger funnet. Opprett nedlastingsjobber ved hjelp av Lastn ed knappene som finnes i hele appen.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installerer {0}", + "PackageInstallCompleted": "{0} installering fullf\u00f8rt.", + "PackageInstallFailed": "{0} installasjon feilet.", + "PackageInstallCancelled": "{0} installasjon avbrutt.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "et element", + "ValueOneSong": "1 sang", + "ValueSongCount": "{0} sanger", + "ValueOneMovie": "1 film", + "ValueMovieCount": "{0} filmer", + "ValueOneSeries": "1 serie", + "ValueSeriesCount": "{0} serier", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episoder", + "ValueOneGame": "1 spill", + "ValueGameCount": "{0} spill", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} album", + "ValueOneMusicVideo": "1 musikkvideo", + "ValueMusicVideoCount": "{0} musikkvideoer", + "ValueMinutes": "{0} minutter", + "Albums": "Album", + "Songs": "Sanger", + "Books": "B\u00f8ker", + "HeaderAudioBooks": "Lydb\u00f8ker", + "HeaderIdentifyItemHelp": "Oppgi ett eller flere s\u00f8ke kriterier. Fjern kriterie for \u00e5 \u00f8ke s\u00f8ke resultater.", + "PleaseEnterNameOrId": "Vennligst skriv ett navn eller en ekstern id.", + "MessageItemSaved": "Element lagret.", + "SearchResults": "S\u00f8keresultater", + "ServerNameIsRestarting": "Emby Server - {0} starter om.", + "ServerNameIsShuttingDown": "Emby Server - {0} avsluttes.", + "HeaderDeleteItems": "Slett elementer", + "ConfirmDeleteItems": "Sletting av disse elementene vil slette dem fra b\u00e5de filsystemet og mediebiblioteket . Er du sikker p\u00e5 at du vil fortsette?", + "PleaseRestartServerName": "Vennligst start gj\u00f8r en omstart av Emby Server - {0}", + "LabelSyncJobName": "Navn p\u00e5 synkroniseringsjobb:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Kvalitet:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "L\u00e6re mer", + "LabelProfile": "Profil:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Begrenset antall:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Skjermbilder", + "MoveRight": "Flytt h\u00f8yere", + "MoveLeft": "Flytt venstre", + "ConfirmDeleteImage": "Slett bilde?", + "HeaderEditImages": "Endre bilder", + "Settings": "Innstillinger", + "ShowIndicatorsFor": "Vis indikatorer for:", + "NewEpisodes": "Nye episoder", + "Episodes": "Episoder", + "HDPrograms": "HD Programmer", + "Programs": "Programmer", + "LiveBroadcasts": "Direkte sending", + "Premieres": "Premierer", + "RepeatEpisodes": "Gjenta episode", + "DvrSubscriptionRequired": "Emby DVR krever et aktivt Emby Premiere-abonnement.", + "HeaderCancelRecording": "Avbryt opptak", + "CancelRecording": "Avbryt opptak", + "HeaderKeepRecording": "Behold opptak", + "HeaderCancelSeries": "Avbryt serie", + "HeaderKeepSeries": "Behold serie", + "HeaderLearnMore": "L\u00e6r mere", + "DeleteMedia": "Slett elementet", + "SeriesSettings": "Serie innstillinger", + "HeaderRecordingOptions": "Opptak innstillinger", + "CancelSeries": "Avbryt serie", + "DoNotRecord": "Ikke ta opp", + "HeaderSeriesOptions": "Serie innstillinger", + "LabelChannels": "Kanal", + "ChannelNameOnly": "Kun kanal {0}", + "Anytime": "Enhver tid", + "AnyLanguage": "Any language", + "AroundTime": "Rundt {0}", + "All": "All", + "AllChannels": "Alle kanaler", + "LabelRecord": "Opptak:", + "NewEpisodesOnly": "Kun nye episoder", + "AllEpisodes": "Alle episoder", + "LabelStartWhenPossible": "Start n\u00e5r mulig:", + "LabelStopWhenPossible": "Stop n\u00e5r mulig:", + "MinutesBefore": "Minutter f\u00f8r", + "MinutesAfter": "Minutter etter", + "SkipEpisodesAlreadyInMyLibrary": "Ikke ta opp episoder som allerede finnes i biblioteket mitt", + "SkipEpisodesAlreadyInMyLibraryHelp": "Episoder vil bli sammenlignet med sesong- og episode nummer n\u00e5r de er tilgjengelige.", + "LabelKeepUpTo": "Hold opptil", + "AsManyAsPossible": "S\u00e5 mange som mulig", + "DefaultErrorMessage": "Det skjedde en feil under behandling av foresp\u00f8rselen. Vennligst pr\u00f8v igjen senere.", + "LabelKeep:": "Behold", + "UntilIDelete": "Inntil jeg sletter", + "UntilSpaceNeeded": "Inntil lagringsplass er n\u00f8dvendig", + "Categories": "Kategorier", + "Sports": "Sport", + "News": "Nyheter", + "Movies": "Filmer", + "Kids": "Barn", + "EnableColorCodedBackgrounds": "Aktiver fargekoder for bakgrunn", + "SortChannelsBy": "Sorter kanaler etter", + "RecentlyWatched": "Nylig sett", + "ChannelNumber": "Kanal nummer", + "HeaderBenefitsEmbyPremiere": "Fordeler med Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "Vennligst nyt ett minutt av avspilling. Takk for at du pr\u00f8ver Emby.", + "HeaderTryPlayback": "Pr\u00f8v tilbakespilling", + "HowDidYouPay": "Hvordan betalte du?", + "IHaveEmbyPremiere": "Jeg har Emby Premiere", + "IPurchasedThisApp": "Jeg har kj\u00f8pt denne appen", + "ButtonRestorePreviousPurchase": "Gjenopprett kj\u00f8p", + "ButtonUnlockWithPurchase": "L\u00e5s opp ved kj\u00f8p", + "ButtonUnlockPrice": "L\u00e5s opp {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere m\u00e5nedlig {0}", + "HeaderAlreadyPaid": "Allerede betalt?", + "ButtonPlayOneMinute": "Spill av et minutt", + "PlaceFavoriteChannelsAtBeginning": "Plasser favorittkanaler i starten", + "HeaderUnlockFeature": "L\u00e5s opp funksjon", + "MessageDidYouKnowCinemaMode": "Visste du at med Emby Premiere kan du forbedre din opplevelse med funksjoner som Kinomodus?", + "MessageDidYouKnowCinemaMode2": "Kinomodus gir deg den ekte kinoopplevelsen med trailere og tilpassede introer f\u00f8r hovedfunksjonen.", + "HeaderPlayMyMedia": "Spill min media", + "HeaderDiscoverEmbyPremiere": "Opplev Emby Premiere", + "Items": "Elementer", + "OneChannel": "En kanal", + "ConfirmRemoveDownload": "Fjern nedlastet?", + "RemoveDownload": "Fjern nedlastet", + "KeepDownload": "Behold nedlasting", + "AddedOnValue": "Lagt til {0}", + "RemovingFromDevice": "Fjerner fra enheten", + "KeepOnDevice": "Behold p\u00e5 enhet", + "CancelDownload": "Avbryt nedlasting", + "SyncJobItemStatusReadyToTransfer": "Klar til overf\u00f8ring", + "SyncJobItemStatusSyncedMarkForRemoval": "Fjern fra enhet", + "SyncJobItemStatusQueued": "K\u00f8", + "SyncJobItemStatusConverting": "Konverter", + "SyncJobItemStatusTransferring": "Overf\u00f8rer", + "SyncJobItemStatusSynced": "Ned lastet", + "SyncJobItemStatusFailed": "Feil", + "SyncJobItemStatusRemovedFromDevice": "Fjernet fra enhet", + "SyncJobItemStatusCancelled": "Kansellert", + "Retry": "Pr\u00f8v igjen", + "HeaderMyDevice": "Min enhet", + "Continue": "Forsett", + "ContinueInSecondsValue": "Forsett om {0} sekunder", + "HeaderRemoteControl": "Fjernkontroll", + "Disconnect": "Koble fra", + "EnableDisplayMirroring": "Aktivert skjermspeiling", + "HeaderPlayOn": "Forsett avspilling", + "Quality": "Kvalitet", + "Auto": "Automatisk", + "AndroidUnlockRestoreHelp": "For \u00e5 gjenopprette tidligere kj\u00f8p, m\u00e5 du forsikre deg om at du er logget p\u00e5 enheten med samme Google- (eller Amazonkonto) som opprinnelig gjorde kj\u00f8pet. Pass p\u00e5 at appbutikken er aktivert og ikke begrenset av foreldrekontroll,samt s\u00f8rg for at du har en aktiv internettforbindelse. Du m\u00e5 bare gj\u00f8re dette en gang for \u00e5 gjenopprette ditt tidligere kj\u00f8p.", + "AspectRatio": "St\u00f8rrelsesforholdet", + "Original": "Original", + "Fill": "Fyll ut", + "BestFit": "Passer best", + "MessageNoServersAvailableToConnect": "Ingen servere tilgjengelig for \u00e5 koble til. Hvis du har blitt invitert til \u00e5 dele en server, m\u00e5 du akseptere den nedenfor eller ved \u00e5 klikke p\u00e5 lenken i e-posten.", + "MessagePlayAccessRestricted": "Avspilling av dette innholdet er for tiden begrenset. Ta kontakt med Emby Server-administratoren for mer informasjon.", + "Accept": "Aksepter", + "Reject": "Avst\u00e5", + "Connect": "Koble til", + "HeaderMyMedia": "Min Media", + "HeaderMyMediaSmall": "Min Media (liten)", + "LatestFromLibrary": "Siste {0}", + "ContinueWatching": "Fortsett \u00e5 se p\u00e5", + "HeaderLatestChannelMedia": "Siste kanalelementer", + "HeaderContinueWatching": "Forsett og se p\u00e5", + "HeaderContinueListening": "Forsett og h\u00f8re p\u00e5", + "HeaderActiveRecordings": "Aktive opptak", + "HeaderLatestRecordings": "Siste opptak", + "LabelSyncTo": "Synkroniser til:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Neste", + "HeaderLatestFrom": "Siste fra {0}", + "LabelHomeScreenSectionValue": "Hjemskjerm seksjon {0}", + "SettingsSaved": "Innstillinger lagret", + "None": "Ingen", + "More": "Mere", + "Up": "Opp", + "Down": "Ned", + "Home": "Home", + "Favorites": "Favoritter", + "HeaderHomeScreen": "Hjemskjerm", + "HeaderLatestChannelItems": "Siste kanal elementer", + "HeaderLibraryOrder": "Bibliotekenes rekkef\u00f8lge", + "HideWatchedContentFromLatestMedia": "Skjul sett innhold fra nyeste media", + "HeaderOnNow": "P\u00e5 N\u00e5", + "HeaderPlaybackError": "Avspillingsfeil", + "PlaybackErrorNotAllowed": "Du er for \u00f8yeblikket ikke autorisert til avspilling dette innholdet. Ta kontakt med systemadministratoren for detaljer.", + "PlaybackErrorNoCompatibleStream": "Ingen kompatible str\u00f8mmer er tilgjengelige for \u00f8yeblikket. Pr\u00f8v igjen senere eller kontakt systemadministratoren for detaljer.", + "PlaybackErrorPlaceHolder": "Sett inn disken for \u00e5 spille av denne filmen.", + "Guide": "Guide", + "Suggestions": "Forslag", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorittspillelister", + "Collections": "Samlinger", + "LabelSelectFolderGroups": "Grupp\u00e9r innhold automatisk etter f\u00f8lgende grupper til visninger som filmer, musikk og TV:", + "LabelSelectFolderGroupsHelp": "Mapper som ikke er merket vil kun bli vist i sin egen visning.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Programmer", + "HeaderLibraryFolders": "Bibliotek mapper", + "HeaderTermsOfPurchase": "Kj\u00f8ps betingelser", + "PrivacyPolicy": "Personvern regler", + "TermsOfUse": "Bruks betingelser", + "RepeatMode": "Repetering modus", + "RepeatOne": "Repetering en", + "RepeatAll": "Repetering alle", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Vill du stenge Emby p\u00e5 denne enheten?", + "Yes": "Ja", + "No": "Nei", + "LiveTV": "Direkte TV", + "Schedule": "Planlegg", + "Recordings": "Opptak", + "MarkWatched": "Marker som sett", + "ScanForNewAndUpdatedFiles": "Se etter nye og oppdaterte filer", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolutt", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Undertekster innstillinger", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Lyd inntilligner", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Spill av neste episode automatisk", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Aktiver kino mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Nyeste media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Spill av neste", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Prim\u00e6rfarger", + "ColorSpace": "Fargeutvalg", + "ColorTransfer": "Overf\u00f8ring av farger", + "VideoRange": "Videoomr\u00e5de", + "SeriesDisplayOrderHelp": "Sorter episoder etter sendt dato, DVD-rekkef\u00f8lge eller nummerering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/nl.json b/src/bower_components/emby-webcomponents/strings/nl.json index 5e9dd29b9c..b6f0f7307a 100644 --- a/src/bower_components/emby-webcomponents/strings/nl.json +++ b/src/bower_components/emby-webcomponents/strings/nl.json @@ -1,685 +1,689 @@ { - "Absolute": "Absoluut", - "Accept": "Accepteren", - "AccessRestrictedTryAgainLater": "Toegang is momenteel bepertk, probeer later opnieuw.", - "Actor": "Acteur", - "Add": "Toevoegen", - "AddToCollection": "Toevoegen aan Collectie", - "AddToPlayQueue": "Toevoegen aan wachtrij", - "AddToPlaylist": "Toevoegen aan afspeellijst", - "AddedOnValue": "{0} Toegevoegd", - "Advanced": "Geavanceerd", - "AirDate": "Uitzenddatum", - "Aired": "Uitgezonden", - "Albums": "Albums", - "All": "Alle", - "AllChannels": "Alle kanalen", - "AllComplexFormats": "Alle complexe formaten (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Alle afleveringen", - "AllLanguages": "Alle talen", - "AllowSeasonalThemes": "Schakel seizoen thema's in", - "AllowSeasonalThemesHelp": "Indien ingeschakeld zullen seizoen thema's uw thema instellingen overschrijven.", - "AlwaysPlaySubtitles": "Altijd ondertitels weergeven", - "AlwaysPlaySubtitlesHelp": "Ondertitels die met de taalvoorkeur overeenkomen worden weergegeven, ongeacht de audiotaal.", - "AnamorphicVideoNotSupported": "Anamorfische video niet ondersteund", - "AndroidUnlockRestoreHelp": "Om uw eerdere aankoop te herstellen, controleert u of u aangemeld bent met hetzelfde Google (of Amazon) account waarmee u de aankoop deed. Controleer dat de app store is ingeschakeld en niet door ouderlijk toezicht wordt tegengehouden en controleer dat u een actieve internet verbinding hebt. U hoeft dit slechts eenmalig te doen om uw eerdere aankoop te herstellen.", - "AnyLanguage": "Elke taal", - "Anytime": "Op elk moment", - "AroundTime": "Rond {0}", - "Art": "Art", - "Artists": "Artiesten", - "AsManyAsPossible": "Zo veel als mogelijk", - "Ascending": "Oplopend", - "AspectRatio": "Beeldverhouding", - "AttemptingWakeServer": "Proberen de server te wekken. Een moment geduld...", - "AttributeNew": "Nieuw", - "AudioBitDepthNotSupported": "Audio bit depth niet ondersteund", - "AudioBitrateNotSupported": "Audio bitrate niet ondersteund", - "AudioChannelsNotSupported": "Audio kanalen niet ondersteund", - "AudioCodecNotSupported": "Audio codec niet ondersteund", - "AudioProfileNotSupported": "Audio profiel niet ondersteund", - "AudioSampleRateNotSupported": "Audio sample rate niet ondersteund", - "Auto": "Automatisch", - "AutoBasedOnLanguageSetting": "Automatisch (gebaseerd op taal instelling)", - "AutomaticallyConvertNewContent": "Nieuwe content automatisch converteren", - "AutomaticallyConvertNewContentHelp": "Nieuwe content toegevoegd aan deze map wordt automatisch geconverteerd.", - "AutomaticallySyncNewContent": "Nieuwe inhoud automatisch downloaden", - "AutomaticallySyncNewContentHelp": "Aan deze map toegevoegde nieuwe inhoud automatisch naar het apparaat downloaden.", - "Backdrop": "Achtergrond", - "Backdrops": "Achtergronden", - "Banner": "Banner", - "BestFit": "Best passend", - "BirthLocation": "Geboorte Locatie", - "Books": "Boeken", - "Box": "Box", - "BoxRear": "Box (achterkant)", - "Browse": "Bladeren", - "BurnSubtitlesHelp": "Bepaalt of de server ondertitels moet inbranden wanneer video's op basis van het ondertitel formaat geconverteerd moeten worden. Inbranden van ondertitels hebben een negatief effect op de server performance. Selecteer Automatisch om op afbeelding gebaseerde formaten (bijv. VOBSUB, PGS, SUB/IDX etc.) en bepaalde ASS/SSA ondertitels in te branden.", - "ButtonCancel": "Annuleren", - "ButtonGotIt": "Begrepen", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Speel één minuut", - "ButtonRestart": "Herstart", - "ButtonRestorePreviousPurchase": "Herstel Aankoop", - "ButtonTryAgain": "Opnieuw Proberen", - "ButtonUnlockPrice": "{0} Vrijgeven", - "ButtonUnlockWithPurchase": "Geef vrij met een aankoop", - "CancelDownload": "Download annuleren", - "CancelRecording": "Opname annuleren", - "CancelSeries": "Annuleer series", - "Categories": "Categorieën", - "ChannelNameOnly": "Alleen kanaal {0}", - "ChannelNumber": "Kanaal nummer", - "CinemaModeConfigurationHelp": "Cinema mode brengt de theater ervaring naar uw woonkamer met de mogelijkheid om trailers en eigen intro's voor de film af te spelen.", - "CinemaModeFeatureDescription": "Bioscoop mode geeft u de ware bioscoopervaring met trailers en aangepaste intro's voor de weergave van uw keuze.", - "CloudSyncFeatureDescription": "Synchroniseer uw media naar de cloud voor eenvoudige backup, archivering en conversie.", - "Collections": "Collecties", - "ColorPrimaries": "Primaire kleuren", - "ColorSpace": "Kleurbereik", - "ColorTransfer": "Kleuroverdracht", - "CommunityRating": "Community-beoordeling", - "Composer": "Componist", - "ConfigureDateAdded": "Configureer hoe datum toegevoegd wordt bepaald in het Jellyfin Server dashboard onder de instellingen van de documentbibliotheek", - "ConfirmDeleteImage": "Afbeelding verwijderen?", - "ConfirmDeleteItem": "Verwijderen van dit item zal het verwijderen uit zowel het bestandssysteem als de Media Bibliotheek. Weet u zeker dat u wilt doorgaan?", - "ConfirmDeleteItems": "Het verwijderen van deze items verwijdert ze van het bestandssysteem en uit uw bibliotheek. Weet u zeker dat u verder wilt gaan?", - "ConfirmDeletion": "Bevestigen Verwijdering", - "ConfirmEndPlayerSession": "Wilt u Jellyfin afsluiten op {0}?", - "ConfirmRemoveDownload": "Download verwijderen?", - "Connect": "Verbind", - "ContainerBitrateExceedsLimit": "Media bitrate overschrijdt limiet.", - "ContainerNotSupported": "Container niet ondersteund", - "Continue": "Hervatten", - "ContinueInSecondsValue": "Hervatten over {0} seconden.", - "ContinueWatching": "Kijken hervatten", - "Continuing": "Wordt vervolgd...", - "Convert": "Converteren", - "ConvertItemLimitHelp": "Optioneel. Stel een maximum aantal items in dat wordt geconverteerd.", - "ConvertUnwatchedVideosOnly": "Alleen onbekeken video's converteren", - "ConvertUnwatchedVideosOnlyHelp": "Alleen onbekeken video's worden geconverteerd.", - "ConvertingDots": "Converteren...", - "Countries": "Landen", - "CriticRating": "Critici-beoordeling", - "DateAdded": "Datum toegevoegd", - "DatePlayed": "Datum afgespeeld", - "Days": "Dagen", - "Default": "Standaard", - "DefaultErrorMessage": "Er is een fout opgetreden. Probeer later opnieuw.", - "DefaultSubtitlesHelp": "Ondertitels worden geladen op basis van de standaard en geforceerd markeringen in de ingesloten metadata. Indien meerdere opties aanwezig zijn zal rekening worden gehouden met de taalvoorkeuren.", - "Delete": "Verwijderen", - "DeleteMedia": "Verwijder media", - "Depressed": "Onderdrukt", - "Descending": "Aflopend", - "Desktop": "Desktop", - "DirectPlayError": "Direct Afspelen fout", - "DirectPlaying": "Direct afspelen", - "DirectStreamHelp1": "De media is compatible met het apparaat wat betreft resolutie en media type (H.264, AC3 etc.), maar is in een incompatible bestandscontainer (.mkv, .avi, .wmv etc.). De video zal on the fly opnieuw worden verpakt voordat deze naar het apparaat wordt gestreamd.", - "DirectStreamHelp2": "Direct streamen van een bestand gebruikt weinig processor kracht zonder verlies van beeldkwaliteit.", - "DirectStreaming": "Direct streamen", - "Director": "Regiseur", - "DirectorValue": "Regisseur: {0}", - "DirectorsValue": "Regisseurs: {0}", - "Disc": "Disk", - "Disconnect": "Loskoppelen", - "Dislike": "Niet leuk", - "Display": "Weergave", - "DisplayInMyMedia": "Op het startscherm weergeven", - "DisplayInOtherHomeScreenSections": "In secties van het startscherm weergeven, zoals \"Recente Media\" en \"Verder Kijken\"", - "DisplayMissingEpisodesWithinSeasons": "Toon ontbrekende afleveringen binnen een seizoen", - "DisplayMissingEpisodesWithinSeasonsHelp": "Dit moet ook worden ingeschakeld voor TV bibliotheken in Jellyfin Server setup.", - "DisplayModeHelp": "Selecteer het scherm type waar u Jellyfin op draait", - "DoNotRecord": "Niet opnemen", - "Down": "Omlaag", - "Download": "Downloaden", - "DownloadItemLimitHelp": "Optioneel. Stel een maximum aantal items in dat wordt gedownload.", - "Downloaded": "Gedownload", - "Downloading": "Downloaden", - "DownloadingDots": "Downloaden...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Schaduw", - "DvrFeatureDescription": "Plan individuele Live TV opnames, serie opnames en meer met Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR vereist een actief Jellyfin Premiere abonnement.", - "Edit": "Bewerken", - "EditImages": "Bewerk afbeeldingen", - "EditMetadata": "Metadata wijzigen", - "EditSubtitles": "Bewerk ondertiteling", - "EnableBackdrops": "Achtergronden inschakelen", - "EnableBackdropsHelp": "Indien ingeschakeld, zullen achtergrondafbeeldingen tijdens het bladeren op de achtergrond worden getoond.", - "EnableCinemaMode": "Cinema Mode inschakelen", - "EnableColorCodedBackgrounds": "Inschakelen van kleur gecodeerde achtergronden", - "EnableDisplayMirroring": "Inschakelen beeld spiegelen", - "EnableExternalVideoPlayers": "Externe video spelers inschakelen", - "EnableExternalVideoPlayersHelp": "Een menu voor externe spelers zal worden getoond bij het afspelen van video's", - "EnableNextVideoInfoOverlay": "Toon informatie over de volgende video tijdens het afspelen", - "EnableNextVideoInfoOverlayHelp": "Toon informatie over de volgende video in de afspeellijst aan het einde van de video", - "EnableThemeSongs": "Herkenningsmelodie inschakelen", - "EnableThemeSongsHelp": "Indien ingeschakeld, zal de herkenningsmelodie tijdens het bladeren op de achtergrond worden afgespeeld.", - "EnableThemeVideos": "Inschakelen thema video's", - "EnableThemeVideosHelp": "Indien ingeschakeld, zullen thema video's tijdens het bladeren op de achtergrond worden afgespeeld.", - "Ended": "Gestopt", - "EndsAtValue": "Eindigt om {0}", - "Episodes": "Afleveringen", - "Error": "Fout", - "ErrorAddingGuestAccount1": "Er was een probleem bij het toevoegen van het Jellyfin Connect account. Heeft uw gast een Jellyfin account aangemaakt? Zij kunnen zich aanmelden op {0}.", - "ErrorAddingGuestAccount2": "Stuur een email naar {0} met daarin uw email adres als die van hen indien u nog steeds problemen heeft.", - "ErrorAddingJellyfinConnectAccount1": "Er was een probleem bij het toevoegen van het Jellyfin Connect account. Hebt u een Jellyfin account aangemaakt? U kunt u aanmelden op {0}.", - "ErrorAddingJellyfinConnectAccount2": "Stuur een email naar {0} vanuit het email adres dat u voor uw Jellyfin account gebruikt indien u nog steeds problemen heeft", - "ErrorConnectServerUnreachable": "Er was een probleem bij het uitvoeren van deze bewerking. Uw server kan de Jellyfin Connect Server op {0} niet bereiken. Controleer dat uw server een actieve internetverbinding heeft en dat de communicatie toegestaan wordt door de firewall en/of security software die u gebruikt.", - "ErrorDeletingItem": "Er was een probleem bij het verwijderen van het item in Jellyfin Server. Controleer dat Jellyfin Server schrijfrechten op de map heeft en probeer het opnieuw.", - "ErrorReachingJellyfinConnect": "Er is een fout opgetreden bij het bereiken van de Jellyfin Connect server. Zorg ervoor dat u een actieve internetverbinding heeft en probeer het opnieuw.", - "ErrorRemovingJellyfinConnectAccount": "Er is een fout opgetreden bij het verwijderen van het Jellyfin Connect acount. Zorg ervoor dat u een actieve internetverbinding heeft en probeer het opnieuw.", - "ExtraLarge": "Extra groot", - "Extras": "Extra's", - "Favorite": "Favoriet", - "Favorites": "Favorieten", - "FeatureRequiresJellyfinPremiere": "Deze functie vereist een actieve Jellyfin Premiere abonnement.", - "Features": "Kenmerken", - "File": "Bestande", - "Fill": "Vullen", - "Filters": "Filters", - "Folders": "Mappen", - "FormatValue": "Formaat: {0}", - "FreeAppsFeatureDescription": "Geniet van gratis toegang tot Jellyfin apps voor uw apparaten.", - "Friday": "Vrijdag", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Groeperen op serie", - "GroupVersions": "Versies groeperen", - "GuestStar": "Gast ster", - "GuestUserNotFound": "Gebruiker is niet gevonden. Zorg ervoor dat de naam klopt en probeer het opnieuw, of probeer hun emailadres in te voeren.", - "Guide": "Gids", - "HDPrograms": "HD Programma's", - "HeaderActiveRecordings": "Actieve Opnames", - "HeaderAddToCollection": "Toevoegen aan Collectie", - "HeaderAddToPlaylist": "Toevoegen aan Afspeellijst", - "HeaderAddUpdateImage": "Afbeelding Toevoegen/Bijwerken", - "HeaderAlbumArtists": "Album Artiesten", - "HeaderAlreadyPaid": "Reeds betaald?", - "HeaderAppearsOn": "Verschijnt op", - "HeaderAudioBooks": "Luisterboeken", - "HeaderAudioSettings": "Audio Instellingen", - "HeaderBecomeProjectSupporter": "Verkrijg Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Voordelen van Jellyfin Premiere", - "HeaderCancelRecording": "Opname Annuleren", - "HeaderCancelSeries": "Annuleren Series", - "HeaderCinemaMode": "Bioscoop mode", - "HeaderCloudSync": "Cloud Synchronisatie", - "HeaderConfirmRecordingCancellation": "Bevestigen Annulering Opname", - "HeaderContinueListening": "Luisteren hervatten", - "HeaderContinueWatching": "Kijken hervatten", - "HeaderConvertYourRecordings": "Opnames omzetten", - "HeaderCustomizeHomeScreen": "Beginscherm aanpassen", - "HeaderDeleteItem": "Item verwijderen", - "HeaderDeleteItems": "Verwijder items", - "HeaderDisplaySettings": "Weergave instellingen", - "HeaderDownloadSettings": "Download Instellingen", - "HeaderEditImages": "Afbeeldingen bewerken", - "HeaderEnabledFields": "Schakel velden in", - "HeaderEnabledFieldsHelp": "Verwijder een vinkje om het veld te vergrendelen en voorkom dat gegevens gewijzigd kunnen worden.", - "HeaderExternalIds": "Externe id's:", - "HeaderFavoriteAlbums": "Favoriete albums", - "HeaderFavoriteArtists": "Favoriete artiesten", - "HeaderFavoriteCollections": "Favoriete collecties", - "HeaderFavoriteEpisodes": "Favoriete afleveringen", - "HeaderFavoriteGames": "Favoriete games", - "HeaderFavoriteMovies": "Favoriete films", - "HeaderFavoritePlaylists": "Favoriete afspeellijsten", - "HeaderFavoriteShows": "Favoriete series", - "HeaderFavoriteSongs": "Favoriete nummers", - "HeaderFavoriteVideos": "Favoriete video's", - "HeaderFreeApps": "Gratis Jellyfin Apps", - "HeaderHomeScreen": "Begin Scherm", - "HeaderIdentifyItemHelp": "Vul één of meer zoek criteria in. Verwijder criteria om zoekresultaten te vergroten.", - "HeaderInvitationSent": "Uitnodiging Verzonden", - "HeaderJellyfinAccountAdded": "Jellyfin Account Toegevoegd", - "HeaderJellyfinAccountRemoved": "Jellyfin Account verwijderd", - "HeaderKeepRecording": "Bewaar opname", - "HeaderKeepSeries": "Series behouden", - "HeaderLatestChannelItems": "Nieuwste Kanaal Items", - "HeaderLatestChannelMedia": "Nieuwste Kanaal Items", - "HeaderLatestFrom": "Laatste van {0}", - "HeaderLatestMedia": "Nieuwste Media", - "HeaderLatestRecordings": "Nieuwste Opnames", - "HeaderLearnMore": "Meer informatie", - "HeaderLibraryFolders": "Bibliotheek Mappen", - "HeaderLibraryOrder": "Bibliotheek Volgorde", - "HeaderMetadataSettings": "Metagegevens instellingen", - "HeaderMusicQuality": "Muziek Kwaliteit", - "HeaderMyDevice": "Mijn Apparaat", - "HeaderMyDownloads": "Mijn Downloads", - "HeaderMyMedia": "Mijn Media", - "HeaderMyMediaSmall": "Mijn Media (klein)", - "HeaderNewRecording": "Nieuwe opname", - "HeaderNextEpisodePlayingInValue": "Volgende Aflevering over {0}", - "HeaderNextUp": "Volgende", - "HeaderNextVideoPlayingInValue": "Volgende Afgespeeld over {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media naar uw apparaten voor gemakkelijk offline gebruik.", - "HeaderOnNow": "Aan het spelen", - "HeaderPhotoAlbums": "Foto-albums", - "HeaderPlayMyMedia": "Mijn Media afspelen", - "HeaderPlayOn": "Afspelen Op", - "HeaderPlaybackError": "Afspeel Fout", - "HeaderRecordingOptions": "Opname instellingen", - "HeaderRemoteControl": "Afstandsbediening", - "HeaderRestartingJellyfinServer": "Jellyfin Server herstarten", - "HeaderSaySomethingLike": "Zeg iets zoals...", - "HeaderSecondsValue": "{0} Seconden", - "HeaderSelectDate": "Selecteer Datum", - "HeaderSeriesOptions": "Series Opties", - "HeaderSeriesStatus": "Seriestatus", - "HeaderSpecialEpisodeInfo": "Speciale afleveringsinformatie", - "HeaderStartNow": "Nu Starten", - "HeaderStopRecording": "Stop Opname", - "HeaderSubtitleAppearance": "Ondertitel Weergave", - "HeaderSubtitleSettings": "Ondertitel Instellingen", - "HeaderSyncRequiresSub": "Downloaden vereist een actief Jellyfin Premiere lidmaatschap.", - "HeaderTermsOfPurchase": "Aankoop Voorwaarden", - "HeaderTryPlayback": "Probeer Afspelen", - "HeaderUnlockFeature": "Ontgrendel Functionaliteit", - "HeaderUploadImage": "Afbeelding Uploaden", - "HeaderVideoQuality": "Video Kwaliteit", - "HeaderVideoType": "Videotype", - "HeaderWaitingForWifi": "Wachten op Wifi", - "HeaderWakeServer": "Server Wekken", - "HeaderYouSaid": "U zei...", - "Help": "Hulp", - "Hide": "Verbergen", - "HideWatchedContentFromLatestMedia": "Verberg gekeken inhoud uit nieuwste media", - "Home": "Start", - "Horizontal": "Horizontaal", - "HowDidYouPay": "Hoe hebt u betaald?", - "IHaveJellyfinPremiere": "Ik heb Jellyfin Premiere", - "IPurchasedThisApp": "Ik heb deze app gekocht", - "Identify": "Identificeer", - "Images": "Afbeeldingen", - "ImdbRating": "IMDb-beoordeling", - "InstallingPackage": "Installeren van {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video niet ondersteund", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Download bewaren", - "KeepOnDevice": "Bewaar op apparaat", - "Kids": "Kinderen", - "Label3DFormat": "3D formaat", - "LabelAirDays": "Uitzend dagen:", - "LabelAirTime": "Uitzend tijd:", - "LabelAirsAfterSeason": "Uitgezonden na seizoen:", - "LabelAirsBeforeEpisode": "Uitgezonden voor aflevering:", - "LabelAirsBeforeSeason": "Uitgezonden voor seizoen:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artiesten:", - "LabelArtists": "Artiest:", - "LabelArtistsHelp": "Scheidt meerdere met een ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Voorkeurs audiotaal:", - "LabelBirthDate": "Geboortedatum:", - "LabelBirthYear": "Geboorte jaar:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Ondertitels inbranden:", - "LabelChannels": "Kanalen:", - "LabelCollection": "Collectie", - "LabelCommunityRating": "Beoordeling gemeenschap:", - "LabelContentType": "Inhoud type:", - "LabelConvertTo": "Converteren naar:", - "LabelCountry": "Land:", - "LabelCriticRating": "Beoordeling critici:", - "LabelCustomRating": "Aangepaste classificatie:", - "LabelDashboardTheme": "Server dashboard thema:", - "LabelDateAdded": "Datum toegevoegd:", - "LabelDateTimeLocale": "Datum en tijd regio:", - "LabelDeathDate": "Overlijdens datum:", - "LabelDefaultScreen": "Standaard scherm:", - "LabelDiscNumber": "Disk nummer:", - "LabelDisplayLanguage": "Schermtaal:", - "LabelDisplayLanguageHelp": "Vertaling van Jellyfin is een voortdurend project.", - "LabelDisplayMode": "Weergave mode:", - "LabelDisplayOrder": "Weergave volgorde:", - "LabelDropImageHere": "Sleep de afbeelding hierheen of klik om te bladeren.", - "LabelDropShadow": "Schaduw:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mailadres:", - "LabelEndDate": "Eind datum|", - "LabelEpisodeNumber": "Afleveringsnummer:", - "LabelFont": "Lettertype:", - "LabelHomeNetworkQuality": "Thuisnetwerk kwaliteit:", - "LabelHomeScreenSectionValue": "Beginscherm sectie {0}:", - "LabelImageType": "Afbeeldingstype:", - "LabelInternetQuality": "Internet kwaliteit:", - "LabelItemLimit": "Item limiet:", - "LabelKeep:": "Houden:", - "LabelKeepUpTo": "Houd tot:", - "LabelLanguage": "Taal:", - "LabelLockItemToPreventChanges": "Vergrendel dit item om toekomstige wijzigingen te voorkomen", - "LabelMaxChromecastBitrate": "Chromecast streaming kwaliteit:", - "LabelMetadataDownloadLanguage": "Voorkeurs taal:", - "LabelName": "Naam:", - "LabelNumber": "Nummer:", - "LabelOriginalAspectRatio": "Originele aspect ratio:", - "LabelOriginalTitle": "Orginele titel:", - "LabelOverview": "Overzicht:", - "LabelParentNumber": "Bovenliggend nummer:", - "LabelParentalRating": "Kijkwijzer classificatie:", - "LabelPath": "Pad:", - "LabelPersonRole": "Rol:", - "LabelPersonRoleHelp": "Voorbeeld: Chauffeur Koeltransport", - "LabelPlaceOfBirth": "Geboorteplaats:", - "LabelPlayDefaultAudioTrack": "Standaard audio spoor afspelen ongeacht de taal", - "LabelPlaylist": "Afspeellijst:", - "LabelPreferredSubtitleLanguage": "Voorkeurstaal ondertitels:", - "LabelProfile": "profiel:", - "LabelQuality": "Kwaliteit", - "LabelReasonForTranscoding": "Reden voor transcoderen:", - "LabelRecord": "Opnemen:", - "LabelRefreshMode": "Vernieuw-modus", - "LabelReleaseDate": "Uitgave datum:", - "LabelRuntimeMinutes": "Speelduur (minuten):", - "LabelScreensaver": "Schermbeveiliging:", - "LabelSeasonNumber": "Seizoensnummer:", - "LabelSelectFolderGroups": "De inhoud van de volgende mappen automatisch groeperen in secties zoals Films, Muziek en TV:", - "LabelSelectFolderGroupsHelp": "Mappen die niet aangevinkt zijn worden getoond in hun eigen weergave.", - "LabelShortOverview": "Kort overzicht:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Terugspoellengte", - "LabelSkipForwardLength": "Vooruitspoellengte", - "LabelSortBy": "Sorteren op:", - "LabelSortOrder": "Sorteervolgorde:", - "LabelSortTitle": "Sorteer titel:", - "LabelSoundEffects": "Geluidseffecten:", - "LabelSource": "Bron:", - "LabelStartWhenPossible": "Start indien mogelijk:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop indien mogelijk:", - "LabelSubtitlePlaybackMode": "Ondertitel mode:", - "LabelSubtitles": "Ondertitels:", - "LabelSyncJobName": "Naam synchroniseer taak:", - "LabelSyncNoTargetsHelp": "Het lijkt erop dat u momenteel geen apps heeft die offline downloaden ondersteunen.", - "LabelSyncTo": "Synchroniseer naar:", - "LabelTVHomeScreen": "TV mode begin scherm", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Tekst achtergrond kleur:", - "LabelTextColor": "Tekst kleur:", - "LabelTextSize": "Tekst grootte:", - "LabelTheme": "Thema:", - "LabelTitle": "Titel:", - "LabelTrackNumber": "Tracknummer:", - "LabelType": "Type:", - "LabelVersion": "Versie:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Tekst achtergrond kleur:", - "LabelYear": "Jaar:", - "Large": "Groot", - "LatestFromLibrary": "Laatste {0}", - "LearnHowYouCanContribute": "Lees meer over hoe u kunt bijdragen.", - "LearnMore": "Meer informatie", - "Like": "Leuk", - "LinksValue": "Links: {0}", - "List": "Lijst", - "Live": "Live", - "LiveBroadcasts": "Live uitzendingen", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV naar een Jellyfin app, met een compatible TV tuner apparaat in uw Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV vereist een actief Jellyfin Premiere lidmaatschap", - "Logo": "Logo", - "ManageRecording": "Beheren opnames", - "MarkPlayed": "Markeren als Afgespeeld", - "MarkUnplayed": "Markeren als Niet Afgespeeld", - "MarkWatched": "Markeer als bekeken", - "MediaIsBeingConverted": "De media wordt geconverteerd naar een formaat dat compatible is met het apparaat dat wordt gebruikt om de media af te spelen.", - "Medium": "Gemiddeld", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Er is een actief Jellyfin Premiere abonnement benodigd om een automatische serie opname aan te maken.", - "MessageAreYouSureDeleteSubtitles": "Weet u zeker dat u dit ondertitelbestand wilt verwijderen?", - "MessageConfirmRecordingCancellation": "Opnemen annuleren?", - "MessageDownloadQueued": "Download in de wachtrij geplaatst.", - "MessageFileReadError": "Er is een fout opgetreden bij het lezen van het bestand. Probeer het opnieuw.", - "MessageIfYouBlockedVoice": "Als u spraak toegang uitgeschakeld heeft moet u dit opnieuw configureren voordat u verder gaat.", - "MessageInvitationSentToNewUser": "Een email is verzonden naar {0} met een uitnodiging om aan te melden bij Jellyfin.", - "MessageInvitationSentToUser": "Een email is verzonden naar {0} met een uitnodiging om uw uitnodiging te accepteren.", - "MessageItemSaved": "Item opgeslagen.", - "MessageItemsAdded": "Items toegevoegd", - "MessageJellyfinAccontRemoved": "Het Jellyfin account is van deze gebruiker verwijderd.", - "MessageJellyfinAccountAdded": "Het Jellyfin account is aan deze gebruiker toegevoegd.", - "MessageLeaveEmptyToInherit": "Leeg laten om instellingen van bovenliggend item of de algemene waarde over te nemen.", - "MessageNoDownloadsFound": "Geen offline downloads. Maak uw media offline beschikbaar door in de app op Download te klikken.", - "MessageNoServersAvailableToConnect": "Er zijn geen servers beschikbaar om mee te verbinden. Als u uitgenodigd bent om een server te delen accepteer dit hieronder of door op de link in het e-mailbericht te klikken.", - "MessageNoSyncJobsFound": "Geen downloads gevonden. Maak download taken met behulp van de Download knoppen in de app.", - "MessagePendingJellyfinAccountAdded": "Het Jellyfin account is aan de gebruiker toegevoegd. Er wordt een email verstuurd naar de eigenaar van het account. De uitnodiging zal moeten worden bevestigd door op de link in de email te klikken.", - "MessagePlayAccessRestricted": "Afspelen hiervan is op dit moment niet toegestaan. Neem contact op met uw Jellyfin Server beheerder voor meer informatie.", - "MessageToValidateSupporter": "Als u een actieve Jellyfin Première abonnement heeft, zorg er dan voor dat u deze activeert in uw Jellyfin Server Dashboard door te klikken op Jellyfin Premiere in het hoofdmenu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Ontgrendel deze functie met een kleine eenmalige aankoop, of met een actief Jellyfin Premiere abonnement.", - "MessageUnlockAppWithSupporter": "Ontgrendel deze functie met een actief Jellyfin Première abonnement.", - "MessageWeDidntRecognizeCommand": "Sorry, dat commande herkennen we niet.", - "MinutesAfter": "minuten na", - "MinutesBefore": "minuten voor", - "Mobile": "Mobiel / Tablet", - "Monday": "Maandag", - "More": "Meer", - "MoveLeft": "Naar links verplaatsen", - "MoveRight": "Naar rechts verplaatsen", - "Movies": "Films", - "MySubtitles": "Mijn Ondertitels", - "Name": "Naam", - "NewCollection": "Nieuwe Collectie", - "NewCollectionHelp": "Collecties maken het u mogelijk om gepersonaliseerde groeperingen van films en andere bibliotheek inhoud te maken.", - "NewCollectionNameExample": "Voorbeeld: Star Wars Collectie", - "NewEpisodes": "Nieuwe afleveringen", - "NewEpisodesOnly": "Alleen nieuwe afleveringen", - "News": "Nieuws", - "Next": "Volgende", - "No": "Nee", - "NoItemsFound": "Geen items gevonden.", - "NoSubtitleSearchResultsFound": "Geen resultaten gevonden.", - "NoSubtitles": "Geen ondertitels", - "NoSubtitlesHelp": "Ondertitels worden niet standaard weergegeven. Deze kunnen tijdens het afspelen handmatig worden ingeschakeld.", - "None": "Geen", - "Normal": "Normaal", - "Off": "Uit", - "OneChannel": "Eén kanaal", - "OnlyForcedSubtitles": "Alleen geforceerde ondertitels", - "OnlyForcedSubtitlesHelp": "Alleen als geforceerd gemarkeerde ondertitels worden geladen.", - "OnlyImageFormats": "Alleen image formaten (VOBSUP, PGS, SUB/IDX etc.)", - "Open": "Openen", - "OptionNew": "Nieuw ...", - "Original": "Origineel", - "OriginalAirDateValue": "Originele uitzenddatum: {0}", - "Overview": "Overzicht", - "PackageInstallCancelled": "{0} installatie geannuleerd.", - "PackageInstallCompleted": "{0} installatie voltooid.", - "PackageInstallFailed": "{0} installatie is mislukt.", - "ParentalRating": "Kijkwijzer classificatie", - "People": "Personen", - "PerfectMatch": "Perfecte match", - "Photos": "Foto's", - "PlaceFavoriteChannelsAtBeginning": "Plaats favoriete kanalen aan het begin", - "Play": "Afspelen", - "PlayAllFromHere": "Speel allemaal vanaf hier", - "PlayCount": "Aantal keer afsgespeeld", - "PlayFromBeginning": "Afspelen vanaf begin", - "PlayNext": "Volgende afspelen", - "PlayNextEpisodeAutomatically": "Speel volgende aflevering automatisch", - "PlaybackErrorNoCompatibleStream": "Geen compatibele streams beschikbaar. Probeer het later opnieuw of neem contact op met de serverbeheerder.", - "PlaybackErrorNotAllowed": "U bent niet bevoegd om deze content af te spelen. Neem contact op met uw systeembeheerder voor meer informatie.", - "PlaybackErrorPlaceHolder": "De gekozen content is niet af te spelen vanaf dit apparaat. Plaats de schijf.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "Om de standaard afspeelinstellingen te configureren, stopt u het afspelen van de video. Vervolgens klikt u op het gebruikersicoon in de rechterbovenhoek van de app.", - "Played": "Afgespeeld", - "Playlists": "Afspeellijsten", - "PleaseEnterNameOrId": "Voer een naam of een externe Id in", - "PleaseRestartServerName": "Herstart Jellyfin Server - {0} aub.", - "PleaseSelectDeviceToSyncTo": "Selecteer een apparaat om naar te downloaden", - "PleaseSelectTwoItems": "Selecteer ten minste twee items.", - "Premiere": "Premiere", - "Premieres": "Premières", - "Previous": "Vorige", - "Primary": "Primair", - "PrivacyPolicy": "Privacy beleid", - "Producer": "Producent", - "ProductionLocations": "Productie Locaties", - "Programs": "Programma's", - "PromoConvertRecordingsToStreamingFormat": "Automatisch converteren opnames naar een streaming formaat met Jellyfin Premiere. Opnames zullen on the fly worden omgezet naar MP4 of MKV, op basis van deJellyfin server instellingen.", - "Quality": "Kwaliteit", - "QueueAllFromHere": "Plaats in de wachtrij vanaf hier", - "Raised": "Verhoogd", - "RecentlyWatched": "Onlangs bekeken", - "Record": "Opnemen", - "RecordSeries": "Series Opnemen", - "RecordingCancelled": "Opname geannuleerd.", - "RecordingScheduled": "Opname schema", - "Recordings": "Opnames", - "RefFramesNotSupported": "Aantal video reference frames niet ondersteund", - "Refresh": "Vernieuwen", - "RefreshDialogHelp": "Metadata wordt vernieuwd op basis van de instellingen en internet diensten die zijn ingeschakeld in het dashboard van de Jellyfin Server.", - "RefreshMetadata": "Metadata vernieuwen", - "RefreshQueued": "Vernieuwen wachtrij", - "Reject": "Weigeren", - "ReleaseDate": "Uitgave datum", - "RemoveDownload": "Download verwijderen", - "RemoveFromCollection": "Verwijder uit collectie", - "RemoveFromPlaylist": "Verwijderen uit afspeellijst", - "RemovingFromDevice": "Verwijderen van apparaat", - "Repeat": "Herhaling", - "RepeatAll": "Alle herhalen", - "RepeatEpisodes": "Herhaal afleveringen", - "RepeatMode": "Herhaal mode", - "RepeatOne": "Eén herhalen", - "ReplaceAllMetadata": "Alle metadata vervangen", - "ReplaceExistingImages": "Bestaande afbeeldingen vervangen", - "RestartPleaseWaitMessage": "Wacht totdat Jellyfin Server is afgesloten en opnieuw is gestart. Dit kan een paar minuten duren.", - "ResumeAt": "Hervatten vanaf {0}", - "Retry": "Opnieuw proberen", - "RunAtStartup": "Uitvoeren bij opstarten", - "Runtime": "Speelduur", - "Saturday": "Zaterdag", - "Save": "Opslaan", - "ScanForNewAndUpdatedFiles": "Scan op nieuwe en bijgewerkte bestanden", - "Schedule": "Schema", - "Screenshot": "Schermafdruk", - "Screenshots": "Screenshots", - "Search": "Zoeken", - "SearchForCollectionInternetMetadata": "Zoeken op het internet voor afbeeldingen en metadata", - "SearchForMissingMetadata": "Zoeken naar missende metadata", - "SearchForSubtitles": "Zoeken naar ondertitels", - "SearchResults": "Zoekresultaten", - "SecondaryAudioNotSupported": "Switchen van audiotaal niet ondersteund", - "SeriesCancelled": "Serie geannuleerd.", - "SeriesDisplayOrderHelp": "Afleveringen sorteren op uitzenddatum, DVD-volgorde, of absolute nummering.", - "SeriesRecordingScheduled": "Serieopname gepland.", - "SeriesSettings": "Series instellingen", - "SeriesYearToPresent": "{0} - Heden", - "ServerNameIsRestarting": "Jellyfin Server - {0} is opnieuw aan het opstarten.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is aan het afsluiten.", - "ServerUpdateNeeded": "Deze Jellyfin Server moet worden bijgewerkt. Om de laatste versie te downloaden, gaat u naar {0}", - "Settings": "Instellingen", - "SettingsSaved": "Instellingen opgeslagen.", - "Share": "Delen", - "ShowIndicatorsFor": "Toon indicatoren voor:", - "ShowTitle": "Toon titel", - "ShowYear": "Toon jaar", - "Shows": "Series", - "Shuffle": "Willekeurig", - "SkipEpisodesAlreadyInMyLibrary": "Neem geen afleveringen op die al in mijn bibliotheek aanwezig zijn", - "SkipEpisodesAlreadyInMyLibraryHelp": "Afleveringen zullen worden vergeleken met behulp van seizoen en aflevering nummers, indien beschikbaar.", - "Small": "Klein", - "SmallCaps": "Klein kapitaal", - "Smaller": "Kleiner", - "Smart": "Slim", - "SmartSubtitlesHelp": "Ondertitels worden weergegeven in de voorkeurstaal als de audio in een andere taal zijn.", - "Songs": "Nummers", - "Sort": "Sorteren", - "SortByValue": "Sorteren op {0}", - "SortChannelsBy": "Sorteer kanalen op:", - "SortName": "Sorteerbaar", - "Sports": "Sports", - "StatsForNerds": "Statistieken voor nerds", - "StopRecording": "Stop opname", - "Studios": "Studio's", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Deze instellingen hebben ook effect op afspelen naar een Chromecast wanneer deze vanaf dit apparaat worden gestart.", - "SubtitleAppearanceSettingsDisclaimer": "Deze instellingen hebben geen invloed op grafische ondertitels (PGS, DVD etc.) en ondertitels die hun eigen stijl ingebouwd hebben (ASS/SSA).", - "SubtitleCodecNotSupported": "Ondertitel formaat niet ondersteund", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "Om de standaard ondertiteling- en taalinstellingen te configureren, stopt u het afspelen van de video. Vervolgens klikt u op het gebruikersicoon in de rechterbovenhoek van de app.", - "Subtitles": "Ondertiteling", - "Suggestions": "Suggesties", - "Sunday": "Zondag", - "Sync": "Synchronisatie", - "SyncJobItemStatusCancelled": "Geannuleerd", - "SyncJobItemStatusConverting": "Converteren", - "SyncJobItemStatusFailed": "Mislukt", - "SyncJobItemStatusQueued": "In wachtrij", - "SyncJobItemStatusReadyToTransfer": "Klaar om te Verzenden", - "SyncJobItemStatusRemovedFromDevice": "Verwijderd van apparaat", - "SyncJobItemStatusSynced": "Gedownload", - "SyncJobItemStatusSyncedMarkForRemoval": "Verwijderen van apparaat", - "SyncJobItemStatusTransferring": "Verzenden", - "SyncUnwatchedVideosOnly": "Alleen niet bekeken video's downloaden", - "SyncUnwatchedVideosOnlyHelp": "Alleen niet bekeken video's zullen worden gedownload en de video's worden van het apparaat verwijderd nadat deze zijn bekeken.", - "SyncingDots": "Synchroniseren...", - "TV": "TV", - "Tags": "Labels", - "TagsValue": "Labels: {0}", - "TermsOfUse": "Gebruiksvoorwaarden", - "ThankYouForTryingEnjoyOneMinute": "U kunt nu genieten van één minuut afspelen. Bedankt voor het uitproberen van Jellyfin.", - "ThemeSongs": "Themamuziek", - "ThemeVideos": "Themavideo's", - "TheseSettingsAffectSubtitlesOnThisDevice": "Deze instellingen betreffen ondertitels op dit apparaat", - "Thumb": "Miniatuur", - "Thursday": "Donderdag", - "TrackCount": "{0} nummers", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoderen", - "TryMultiSelect": "Probeer multi-select", - "TryMultiSelectMessage": "Als u meerdere media-items wilt bewerken, klikt u er op een poster en hou even vast, selecteer nu de items die u wilt beheren. Probeer maar!", - "Tuesday": "Dinsdag", - "Uniform": "Uniform", - "UnlockGuide": "Gids vrijgeven", - "Unplayed": "Niet afgespeeld", - "Unrated": "Geen rating", - "UntilIDelete": "Totdat ik verwijder", - "UntilSpaceNeeded": "Totdat de ruimte nodig is", - "Up": "Omhoog", - "Upload": "Uploaden", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} afleveringen", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} films", - "ValueMusicVideoCount": "{0} muziek video's", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 aflevering", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 film", - "ValueOneMusicVideo": "1 muziek video", - "ValueOneSeries": "1 serie", - "ValueOneSong": "1 titel", - "ValueSeconds": "{0} seconden", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} titels", - "ValueSpecialEpisodeName": "Speciaal - {0}", - "Vertical": "Verticaal", - "VideoBitDepthNotSupported": "Video bit depth niet ondersteund", - "VideoCodecNotSupported": "Video codec niet ondersteund", - "VideoFramerateNotSupported": "Video framerate niet ondersteund", - "VideoLevelNotSupported": "Video niveau niet ondersteund", - "VideoProfileNotSupported": "Video profiel niet ondersteund", - "VideoRange": "Videobereik", - "VideoResolutionNotSupported": "Video resolutie niet ondersteund", - "ViewAlbum": "Bekijk album", - "ViewArtist": "Bekijk artiest", - "VoiceInput": "Spraak invoer", - "WakeServer": "Server wekken", - "WakeServerError": "Er zijn \"Wake On Lan\" pakketten naar de server verzonden, maar verbinding maken is mislukt. Het kan voorkomen dat de server wat meer tijd nodig heeft om op te starten, of misschien is Jellyfin Server niet actief op de machine.", - "WakeServerSuccess": "Succesvol!", - "Watched": "Bekeken", - "Wednesday": "Woensdag", - "WifiRequiredToDownload": "Wifi verbinding is vereist om te downloaden.", - "Writer": "Schrijver", - "Yes": "Ja" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "Ontgrendel deze functie met een kleine eenmalige aankoop, of met een actief Emby Premiere abonnement.", + "MessageUnlockAppWithSupporter": "Ontgrendel deze functie met een actief Emby Premi\u00e8re abonnement.", + "MessageToValidateSupporter": "Als u een actieve Emby Premi\u00e8re abonnement heeft, zorg er dan voor dat u deze activeert in uw Emby Server Dashboard door te klikken op Emby Premiere in het hoofdmenu.", + "ValueSpecialEpisodeName": "Speciaal - {0}", + "Share": "Delen", + "Add": "Toevoegen", + "ServerUpdateNeeded": "Deze Emby Server moet worden bijgewerkt. Om de laatste versie te downloaden, gaat u naar {0}", + "LiveTvRequiresUnlock": "Live TV vereist een actief Emby Premiere lidmaatschap", + "AttributeNew": "Nieuw", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Herhaling", + "TrackCount": "{0} nummers", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Originele uitzenddatum: {0}", + "EndsAtValue": "Eindigt om {0}", + "HeaderSelectDate": "Selecteer Datum", + "Watched": "Bekeken", + "AirDate": "Uitzenddatum", + "Played": "Afgespeeld", + "ButtonOk": "Ok", + "ButtonCancel": "Annuleren", + "AccessRestrictedTryAgainLater": "Toegang is momenteel bepertk, probeer later opnieuw.", + "ButtonGotIt": "Begrepen", + "ButtonRestart": "Herstart", + "RecordingCancelled": "Opname geannuleerd.", + "SeriesCancelled": "Serie geannuleerd.", + "RecordingScheduled": "Opname schema", + "SeriesRecordingScheduled": "Serieopname gepland.", + "HeaderNewRecording": "Nieuwe opname", + "WakeServer": "Server wekken", + "HeaderWakeServer": "Server Wekken", + "AttemptingWakeServer": "Proberen de server te wekken. Een moment geduld...", + "WakeServerSuccess": "Succesvol!", + "HeaderCustomizeHomeScreen": "Beginscherm aanpassen", + "WakeServerError": "Er zijn \"Wake On Lan\" pakketten naar de server verzonden, maar verbinding maken is mislukt. Het kan voorkomen dat de server wat meer tijd nodig heeft om op te starten, of misschien is Emby Server niet actief op de machine.", + "Sunday": "Zondag", + "Monday": "Maandag", + "Tuesday": "Dinsdag", + "Wednesday": "Woensdag", + "Thursday": "Donderdag", + "Friday": "Vrijdag", + "Saturday": "Zaterdag", + "Days": "Dagen", + "SortByValue": "Sorteren op {0}", + "LabelSortBy": "Sorteren op:", + "LabelSortOrder": "Sorteervolgorde:", + "HeaderPhotoAlbums": "Foto-albums", + "Photos": "Foto's", + "HeaderAppearsOn": "Verschijnt op", + "List": "Lijst", + "RecordSeries": "Series Opnemen", + "HeaderCinemaMode": "Bioscoop mode", + "HeaderCloudSync": "Cloud Synchronisatie", + "Downloads": "Downloads", + "HeaderMyDownloads": "Mijn Downloads", + "HeaderOfflineDownloads": "Offline Media", + "HeaderOfflineDownloadsDescription": "Download media naar uw apparaten voor gemakkelijk offline gebruik.", + "CloudSyncFeatureDescription": "Synchroniseer uw media naar de cloud voor eenvoudige backup, archivering en conversie.", + "LiveTvFeatureDescription": "Stream Live TV naar een Emby app, met een compatible TV tuner apparaat in uw Emby Server.", + "DvrFeatureDescription": "Plan individuele Live TV opnames, serie opnames en meer met Emby DVR.", + "CinemaModeFeatureDescription": "Bioscoop mode geeft u de ware bioscoopervaring met trailers en aangepaste intro's voor de weergave van uw keuze.", + "HeaderFreeApps": "Gratis Emby Apps", + "FreeAppsFeatureDescription": "Geniet van gratis toegang tot Emby apps voor uw apparaten.", + "HeaderBecomeProjectSupporter": "Verkrijg Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Er is een actief Emby Premiere abonnement benodigd om een automatische serie opname aan te maken.", + "LabelEmailAddress": "E-mailadres:", + "PromoConvertRecordingsToStreamingFormat": "Automatisch converteren opnames naar een streaming formaat met Emby Premiere. Opnames zullen on the fly worden omgezet naar MP4 of MKV, op basis van deEmby server instellingen.", + "FeatureRequiresEmbyPremiere": "Deze functie vereist een actieve Emby Premiere abonnement.", + "HeaderConvertYourRecordings": "Opnames omzetten", + "Record": "Opnemen", + "Save": "Opslaan", + "Edit": "Bewerken", + "Download": "Downloaden", + "Downloaded": "Gedownload", + "Downloading": "Downloaden", + "Advanced": "Geavanceerd", + "Delete": "Verwijderen", + "HeaderDeleteItem": "Item verwijderen", + "ConfirmDeleteItem": "Verwijderen van dit item zal het verwijderen uit zowel het bestandssysteem als de Media Bibliotheek. Weet u zeker dat u wilt doorgaan?", + "Refresh": "Vernieuwen", + "RefreshQueued": "Vernieuwen wachtrij", + "AddToCollection": "Toevoegen aan Collectie", + "HeaderAddToCollection": "Toevoegen aan Collectie", + "NewCollection": "Nieuwe Collectie", + "LabelCollection": "Collectie", + "Help": "Hulp", + "LabelDisplayMode": "Weergave mode:", + "Desktop": "Desktop", + "Mobile": "Mobiel \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Selecteer het scherm type waar u Emby op draait", + "LabelDisplayLanguage": "Schermtaal:", + "LabelDisplayLanguageHelp": "Vertaling van Emby is een voortdurend project.", + "LearnHowYouCanContribute": "Lees meer over hoe u kunt bijdragen.", + "NewCollectionHelp": "Collecties maken het u mogelijk om gepersonaliseerde groeperingen van films en andere bibliotheek inhoud te maken.", + "SearchForCollectionInternetMetadata": "Zoeken op het internet voor afbeeldingen en metadata", + "DisplayMissingEpisodesWithinSeasons": "Toon ontbrekende afleveringen binnen een seizoen", + "DisplayMissingEpisodesWithinSeasonsHelp": "Dit moet ook worden ingeschakeld voor TV bibliotheken in Emby Server setup.", + "EnableThemeSongs": "Herkenningsmelodie inschakelen", + "EnableBackdrops": "Achtergronden inschakelen", + "EnableThemeSongsHelp": "Indien ingeschakeld, zal de herkenningsmelodie tijdens het bladeren op de achtergrond worden afgespeeld.", + "EnableBackdropsHelp": "Indien ingeschakeld, zullen achtergrondafbeeldingen tijdens het bladeren op de achtergrond worden getoond.", + "EnableThemeVideos": "Inschakelen thema video's", + "EnableThemeVideosHelp": "Indien ingeschakeld, zullen thema video's tijdens het bladeren op de achtergrond worden afgespeeld.", + "RunAtStartup": "Uitvoeren bij opstarten", + "LabelScreensaver": "Schermbeveiliging:", + "LabelSoundEffects": "Geluidseffecten:", + "LabelSkin": "Skin:", + "LabelName": "Naam:", + "NewCollectionNameExample": "Voorbeeld: Star Wars Collectie", + "MessageItemsAdded": "Items toegevoegd", + "OptionNew": "Nieuw ...", + "LabelPlaylist": "Afspeellijst:", + "AddToPlaylist": "Toevoegen aan afspeellijst", + "HeaderAddToPlaylist": "Toevoegen aan Afspeellijst", + "Subtitles": "Ondertiteling", + "LabelTheme": "Thema:", + "LabelDashboardTheme": "Server dashboard thema:", + "SearchForSubtitles": "Zoeken naar ondertitels", + "LabelLanguage": "Taal:", + "Search": "Zoeken", + "NoSubtitleSearchResultsFound": "Geen resultaten gevonden.", + "File": "Bestande", + "MessageAreYouSureDeleteSubtitles": "Weet u zeker dat u dit ondertitelbestand wilt verwijderen?", + "ConfirmDeletion": "Bevestigen Verwijdering", + "MySubtitles": "Mijn Ondertitels", + "MessageDownloadQueued": "Download in de wachtrij geplaatst.", + "EditSubtitles": "Bewerk ondertiteling", + "UnlockGuide": "Gids vrijgeven", + "RefreshMetadata": "Metadata vernieuwen", + "ReplaceExistingImages": "Bestaande afbeeldingen vervangen", + "ReplaceAllMetadata": "Alle metadata vervangen", + "SearchForMissingMetadata": "Zoeken naar missende metadata", + "LabelRefreshMode": "Vernieuw-modus", + "NoItemsFound": "Geen items gevonden.", + "HeaderSaySomethingLike": "Zeg iets zoals...", + "ButtonTryAgain": "Opnieuw Proberen", + "HeaderYouSaid": "U zei...", + "MessageWeDidntRecognizeCommand": "Sorry, dat commande herkennen we niet.", + "MessageIfYouBlockedVoice": "Als u spraak toegang uitgeschakeld heeft moet u dit opnieuw configureren voordat u verder gaat.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Geen rating", + "Favorite": "Favoriet", + "Like": "Leuk", + "Dislike": "Niet leuk", + "RefreshDialogHelp": "Metadata wordt vernieuwd op basis van de instellingen en internet diensten die zijn ingeschakeld in het dashboard van de Emby Server.", + "Open": "Openen", + "Play": "Afspelen", + "AddToPlayQueue": "Toevoegen aan wachtrij", + "Shuffle": "Willekeurig", + "Identify": "Identificeer", + "EditImages": "Bewerk afbeeldingen", + "EditMetadata": "Metadata wijzigen", + "Convert": "Converteren", + "Sync": "Synchronisatie", + "InstantMix": "Instant mix", + "ViewAlbum": "Bekijk album", + "ViewArtist": "Bekijk artiest", + "QueueAllFromHere": "Plaats in de wachtrij vanaf hier", + "PlayAllFromHere": "Speel allemaal vanaf hier", + "PlayFromBeginning": "Afspelen vanaf begin", + "ResumeAt": "Hervatten vanaf {0}", + "RemoveFromPlaylist": "Verwijderen uit afspeellijst", + "RemoveFromCollection": "Verwijder uit collectie", + "Sort": "Sorteren", + "Trailer": "Trailer", + "MarkPlayed": "Markeren als Afgespeeld", + "MarkUnplayed": "Markeren als Niet Afgespeeld", + "GroupVersions": "Versies groeperen", + "PleaseSelectTwoItems": "Selecteer ten minste twee items.", + "TryMultiSelect": "Probeer multi-select", + "TryMultiSelectMessage": "Als u meerdere media-items wilt bewerken, klikt u er op een poster en hou even vast, selecteer nu de items die u wilt beheren. Probeer maar!", + "HeaderConfirmRecordingCancellation": "Bevestigen Annulering Opname", + "MessageConfirmRecordingCancellation": "Opnemen annuleren?", + "Error": "Fout", + "VoiceInput": "Spraak invoer", + "LabelContentType": "Inhoud type:", + "LabelPath": "Pad:", + "Playlists": "Afspeellijsten", + "LabelTitle": "Titel:", + "LabelOriginalTitle": "Orginele titel:", + "LabelSortTitle": "Sorteer titel:", + "LabelDateAdded": "Datum toegevoegd:", + "DateAdded": "Datum toegevoegd", + "DatePlayed": "Datum afgespeeld", + "ConfigureDateAdded": "Configureer hoe datum toegevoegd wordt bepaald in het Emby Server dashboard onder de instellingen van de documentbibliotheek", + "LabelStatus": "Status:", + "LabelArtists": "Artiest:", + "LabelArtistsHelp": "Scheidt meerdere met een ;", + "HeaderAlbumArtists": "Album Artiesten", + "LabelAlbumArtists": "Album artiesten:", + "LabelAlbum": "Album:", + "Artists": "Artiesten", + "ImdbRating": "IMDb-beoordeling", + "CommunityRating": "Community-beoordeling", + "LabelCommunityRating": "Beoordeling gemeenschap:", + "LabelCriticRating": "Beoordeling critici:", + "CriticRating": "Critici-beoordeling", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overzicht:", + "LabelShortOverview": "Kort overzicht:", + "LabelReleaseDate": "Uitgave datum:", + "LabelYear": "Jaar:", + "LabelPlaceOfBirth": "Geboorteplaats:", + "Aired": "Uitgezonden", + "LabelAirDays": "Uitzend dagen:", + "LabelAirTime": "Uitzend tijd:", + "LabelRuntimeMinutes": "Speelduur (minuten):", + "LabelParentalRating": "Kijkwijzer classificatie:", + "LabelCustomRating": "Aangepaste classificatie:", + "LabelOriginalAspectRatio": "Originele aspect ratio:", + "Label3DFormat": "3D formaat", + "FormatValue": "Formaat: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfecte match", + "EnableExternalVideoPlayers": "Externe video spelers inschakelen", + "EnableExternalVideoPlayersHelp": "Een menu voor externe spelers zal worden getoond bij het afspelen van video's", + "HeaderSpecialEpisodeInfo": "Speciale afleveringsinformatie", + "LabelAirsBeforeSeason": "Uitgezonden voor seizoen:", + "LabelAirsAfterSeason": "Uitgezonden na seizoen:", + "LabelAirsBeforeEpisode": "Uitgezonden voor aflevering:", + "HeaderExternalIds": "Externe id's:", + "HeaderDisplaySettings": "Weergave instellingen", + "LabelDisplayOrder": "Weergave volgorde:", + "Display": "Weergave", + "Countries": "Landen", + "Genres": "Genres", + "Studios": "Studio's", + "Tags": "Labels", + "HeaderMetadataSettings": "Metagegevens instellingen", + "People": "Personen", + "LabelMetadataDownloadLanguage": "Voorkeurs taal:", + "LabelLockItemToPreventChanges": "Vergrendel dit item om toekomstige wijzigingen te voorkomen", + "MessageLeaveEmptyToInherit": "Leeg laten om instellingen van bovenliggend item of de algemene waarde over te nemen.", + "LabelCountry": "Land:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Geboorte jaar:", + "LabelBirthDate": "Geboortedatum:", + "LabelDeathDate": "Overlijdens datum:", + "LabelEndDate": "Eind datum|", + "LabelSeasonNumber": "Seizoensnummer:", + "LabelEpisodeNumber": "Afleveringsnummer:", + "LabelTrackNumber": "Tracknummer:", + "LabelNumber": "Nummer:", + "LabelDiscNumber": "Disk nummer:", + "LabelParentNumber": "Bovenliggend nummer:", + "SortName": "Sorteerbaar", + "ReleaseDate": "Uitgave datum", + "Continuing": "Wordt vervolgd...", + "Ended": "Gestopt", + "HeaderEnabledFields": "Schakel velden in", + "HeaderEnabledFieldsHelp": "Verwijder een vinkje om het veld te vergrendelen en voorkom dat gegevens gewijzigd kunnen worden.", + "Backdrops": "Achtergronden", + "Images": "Afbeeldingen", + "Runtime": "Speelduur", + "ProductionLocations": "Productie Locaties", + "BirthLocation": "Geboorte Locatie", + "ParentalRating": "Kijkwijzer classificatie", + "PlayCount": "Aantal keer afsgespeeld", + "Name": "Naam", + "Overview": "Overzicht", + "LabelType": "Type:", + "LabelPersonRole": "Rol:", + "LabelPersonRoleHelp": "Voorbeeld: Chauffeur Koeltransport", + "Actor": "Acteur", + "Composer": "Componist", + "Director": "Regiseur", + "GuestStar": "Gast ster", + "Producer": "Producent", + "Writer": "Schrijver", + "MessageNoSyncJobsFound": "Geen downloads gevonden. Maak download taken met behulp van de Download knoppen in de app.", + "MessageNoDownloadsFound": "Geen offline downloads. Maak uw media offline beschikbaar door in de app op Download te klikken.", + "InstallingPackage": "Installeren van {0}", + "PackageInstallCompleted": "{0} installatie voltooid.", + "PackageInstallFailed": "{0} installatie is mislukt.", + "PackageInstallCancelled": "{0} installatie geannuleerd.", + "SeriesYearToPresent": "{0} - Heden", + "ValueOneItem": "1 item", + "ValueOneSong": "1 titel", + "ValueSongCount": "{0} titels", + "ValueOneMovie": "1 film", + "ValueMovieCount": "{0} films", + "ValueOneSeries": "1 serie", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 aflevering", + "ValueEpisodeCount": "{0} afleveringen", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 muziek video", + "ValueMusicVideoCount": "{0} muziek video's", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Nummers", + "Books": "Boeken", + "HeaderAudioBooks": "Luisterboeken", + "HeaderIdentifyItemHelp": "Vul \u00e9\u00e9n of meer zoek criteria in. Verwijder criteria om zoekresultaten te vergroten.", + "PleaseEnterNameOrId": "Voer een naam of een externe Id in", + "MessageItemSaved": "Item opgeslagen.", + "SearchResults": "Zoekresultaten", + "ServerNameIsRestarting": "Emby Server - {0} is opnieuw aan het opstarten.", + "ServerNameIsShuttingDown": "Emby Server - {0} is aan het afsluiten.", + "HeaderDeleteItems": "Verwijder items", + "ConfirmDeleteItems": "Het verwijderen van deze items verwijdert ze van het bestandssysteem en uit uw bibliotheek. Weet u zeker dat u verder wilt gaan?", + "PleaseRestartServerName": "Herstart Emby Server - {0} aub.", + "LabelSyncJobName": "Naam synchroniseer taak:", + "SyncingDots": "Synchroniseren...", + "ConvertingDots": "Converteren...", + "LabelQuality": "Kwaliteit", + "LabelSyncNoTargetsHelp": "Het lijkt erop dat u momenteel geen apps heeft die offline downloaden ondersteunen.", + "DownloadingDots": "Downloaden...", + "HeaderSyncRequiresSub": "Downloaden vereist een actief Emby Premiere lidmaatschap.", + "LearnMore": "Meer informatie", + "LabelProfile": "profiel:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Alleen onbekeken video's converteren", + "SyncUnwatchedVideosOnly": "Alleen niet bekeken video's downloaden", + "ConvertUnwatchedVideosOnlyHelp": "Alleen onbekeken video's worden geconverteerd.", + "SyncUnwatchedVideosOnlyHelp": "Alleen niet bekeken video's zullen worden gedownload en de video's worden van het apparaat verwijderd nadat deze zijn bekeken.", + "AutomaticallySyncNewContent": "Nieuwe inhoud automatisch downloaden", + "AutomaticallySyncNewContentHelp": "Aan deze map toegevoegde nieuwe inhoud automatisch naar het apparaat downloaden.", + "AutomaticallyConvertNewContent": "Nieuwe content automatisch converteren", + "AutomaticallyConvertNewContentHelp": "Nieuwe content toegevoegd aan deze map wordt automatisch geconverteerd.", + "LabelItemLimit": "Item limiet:", + "ConvertItemLimitHelp": "Optioneel. Stel een maximum aantal items in dat wordt geconverteerd.", + "DownloadItemLimitHelp": "Optioneel. Stel een maximum aantal items in dat wordt gedownload.", + "PleaseSelectDeviceToSyncTo": "Selecteer een apparaat om naar te downloaden", + "Screenshots": "Screenshots", + "MoveRight": "Naar rechts verplaatsen", + "MoveLeft": "Naar links verplaatsen", + "ConfirmDeleteImage": "Afbeelding verwijderen?", + "HeaderEditImages": "Afbeeldingen bewerken", + "Settings": "Instellingen", + "ShowIndicatorsFor": "Toon indicatoren voor:", + "NewEpisodes": "Nieuwe afleveringen", + "Episodes": "Afleveringen", + "HDPrograms": "HD Programma's", + "Programs": "Programma's", + "LiveBroadcasts": "Live uitzendingen", + "Premieres": "Premi\u00e8res", + "RepeatEpisodes": "Herhaal afleveringen", + "DvrSubscriptionRequired": "Emby DVR vereist een actief Emby Premiere abonnement.", + "HeaderCancelRecording": "Opname Annuleren", + "CancelRecording": "Opname annuleren", + "HeaderKeepRecording": "Bewaar opname", + "HeaderCancelSeries": "Annuleren Series", + "HeaderKeepSeries": "Series behouden", + "HeaderLearnMore": "Meer informatie", + "DeleteMedia": "Verwijder media", + "SeriesSettings": "Series instellingen", + "HeaderRecordingOptions": "Opname instellingen", + "CancelSeries": "Annuleer series", + "DoNotRecord": "Niet opnemen", + "HeaderSeriesOptions": "Series Opties", + "LabelChannels": "Kanalen:", + "ChannelNameOnly": "Alleen kanaal {0}", + "Anytime": "Op elk moment", + "AnyLanguage": "Elke taal", + "AroundTime": "Rond {0}", + "All": "Alle", + "AllChannels": "Alle kanalen", + "LabelRecord": "Opnemen:", + "NewEpisodesOnly": "Alleen nieuwe afleveringen", + "AllEpisodes": "Alle afleveringen", + "LabelStartWhenPossible": "Start indien mogelijk:", + "LabelStopWhenPossible": "Stop indien mogelijk:", + "MinutesBefore": "minuten voor", + "MinutesAfter": "minuten na", + "SkipEpisodesAlreadyInMyLibrary": "Neem geen afleveringen op die al in mijn bibliotheek aanwezig zijn", + "SkipEpisodesAlreadyInMyLibraryHelp": "Afleveringen zullen worden vergeleken met behulp van seizoen en aflevering nummers, indien beschikbaar.", + "LabelKeepUpTo": "Houd tot:", + "AsManyAsPossible": "Zo veel als mogelijk", + "DefaultErrorMessage": "Er is een fout opgetreden. Probeer later opnieuw.", + "LabelKeep:": "Houden:", + "UntilIDelete": "Totdat ik verwijder", + "UntilSpaceNeeded": "Totdat de ruimte nodig is", + "Categories": "Categorie\u00ebn", + "Sports": "Sports", + "News": "Nieuws", + "Movies": "Films", + "Kids": "Kinderen", + "EnableColorCodedBackgrounds": "Inschakelen van kleur gecodeerde achtergronden", + "SortChannelsBy": "Sorteer kanalen op:", + "RecentlyWatched": "Onlangs bekeken", + "ChannelNumber": "Kanaal nummer", + "HeaderBenefitsEmbyPremiere": "Voordelen van Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "U kunt nu genieten van \u00e9\u00e9n minuut afspelen. Bedankt voor het uitproberen van Emby.", + "HeaderTryPlayback": "Probeer Afspelen", + "HowDidYouPay": "Hoe hebt u betaald?", + "IHaveEmbyPremiere": "Ik heb Emby Premiere", + "IPurchasedThisApp": "Ik heb deze app gekocht", + "ButtonRestorePreviousPurchase": "Herstel Aankoop", + "ButtonUnlockWithPurchase": "Geef vrij met een aankoop", + "ButtonUnlockPrice": "{0} Vrijgeven", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere Maandelijks {0}", + "HeaderAlreadyPaid": "Reeds betaald?", + "ButtonPlayOneMinute": "Speel \u00e9\u00e9n minuut", + "PlaceFavoriteChannelsAtBeginning": "Plaats favoriete kanalen aan het begin", + "HeaderUnlockFeature": "Ontgrendel Functionaliteit", + "MessageDidYouKnowCinemaMode": "Wist u dat u met Emby Premiere u uw ervaring met functies zoals Cinema Mode kunt verbeteren?", + "MessageDidYouKnowCinemaMode2": "Cinema Mode geeft u de echte bioscoop ervaring met trailers en eigen intro's voordat de film begint.", + "HeaderPlayMyMedia": "Mijn Media afspelen", + "HeaderDiscoverEmbyPremiere": "Ontdek Emby Premiere", + "Items": "Items", + "OneChannel": "E\u00e9n kanaal", + "ConfirmRemoveDownload": "Download verwijderen?", + "RemoveDownload": "Download verwijderen", + "KeepDownload": "Download bewaren", + "AddedOnValue": "{0} Toegevoegd", + "RemovingFromDevice": "Verwijderen van apparaat", + "KeepOnDevice": "Bewaar op apparaat", + "CancelDownload": "Download annuleren", + "SyncJobItemStatusReadyToTransfer": "Klaar om te Verzenden", + "SyncJobItemStatusSyncedMarkForRemoval": "Verwijderen van apparaat", + "SyncJobItemStatusQueued": "In wachtrij", + "SyncJobItemStatusConverting": "Converteren", + "SyncJobItemStatusTransferring": "Verzenden", + "SyncJobItemStatusSynced": "Gedownload", + "SyncJobItemStatusFailed": "Mislukt", + "SyncJobItemStatusRemovedFromDevice": "Verwijderd van apparaat", + "SyncJobItemStatusCancelled": "Geannuleerd", + "Retry": "Opnieuw proberen", + "HeaderMyDevice": "Mijn Apparaat", + "Continue": "Hervatten", + "ContinueInSecondsValue": "Hervatten over {0} seconden.", + "HeaderRemoteControl": "Afstandsbediening", + "Disconnect": "Loskoppelen", + "EnableDisplayMirroring": "Inschakelen beeld spiegelen", + "HeaderPlayOn": "Afspelen Op", + "Quality": "Kwaliteit", + "Auto": "Automatisch", + "AndroidUnlockRestoreHelp": "Om uw eerdere aankoop te herstellen, controleert u of u aangemeld bent met hetzelfde Google (of Amazon) account waarmee u de aankoop deed. Controleer dat de app store is ingeschakeld en niet door ouderlijk toezicht wordt tegengehouden en controleer dat u een actieve internet verbinding hebt. U hoeft dit slechts eenmalig te doen om uw eerdere aankoop te herstellen.", + "AspectRatio": "Beeldverhouding", + "Original": "Origineel", + "Fill": "Vullen", + "BestFit": "Best passend", + "MessageNoServersAvailableToConnect": "Er zijn geen servers beschikbaar om mee te verbinden. Als u uitgenodigd bent om een server te delen accepteer dit hieronder of door op de link in het e-mailbericht te klikken.", + "MessagePlayAccessRestricted": "Afspelen hiervan is op dit moment niet toegestaan. Neem contact op met uw Emby Server beheerder voor meer informatie.", + "Accept": "Accepteren", + "Reject": "Weigeren", + "Connect": "Verbind", + "HeaderMyMedia": "Mijn Media", + "HeaderMyMediaSmall": "Mijn Media (klein)", + "LatestFromLibrary": "Laatste {0}", + "ContinueWatching": "Kijken hervatten", + "HeaderLatestChannelMedia": "Nieuwste Kanaal Items", + "HeaderContinueWatching": "Kijken hervatten", + "HeaderContinueListening": "Luisteren hervatten", + "HeaderActiveRecordings": "Actieve Opnames", + "HeaderLatestRecordings": "Nieuwste Opnames", + "LabelSyncTo": "Synchroniseer naar:", + "LabelConvertTo": "Converteren naar:", + "Next": "Volgende", + "LabelSource": "Bron:", + "LabelVersion": "Versie:", + "AllLanguages": "Alle talen", + "Previous": "Vorige", + "HeaderNextUp": "Volgende", + "HeaderLatestFrom": "Laatste van {0}", + "LabelHomeScreenSectionValue": "Beginscherm sectie {0}:", + "SettingsSaved": "Instellingen opgeslagen.", + "None": "Geen", + "More": "Meer", + "Up": "Omhoog", + "Down": "Omlaag", + "Home": "Start", + "Favorites": "Favorieten", + "HeaderHomeScreen": "Begin Scherm", + "HeaderLatestChannelItems": "Nieuwste Kanaal Items", + "HeaderLibraryOrder": "Bibliotheek Volgorde", + "HideWatchedContentFromLatestMedia": "Verberg gekeken inhoud uit nieuwste media", + "HeaderOnNow": "Aan het spelen", + "HeaderPlaybackError": "Afspeel Fout", + "PlaybackErrorNotAllowed": "U bent niet bevoegd om deze content af te spelen. Neem contact op met uw systeembeheerder voor meer informatie.", + "PlaybackErrorNoCompatibleStream": "Geen compatibele streams beschikbaar. Probeer het later opnieuw of neem contact op met de serverbeheerder.", + "PlaybackErrorPlaceHolder": "De gekozen content is niet af te spelen vanaf dit apparaat. Plaats de schijf.", + "Guide": "Gids", + "Suggestions": "Suggesties", + "HeaderFavoriteCollections": "Favoriete collecties", + "HeaderFavoritePlaylists": "Favoriete afspeellijsten", + "Collections": "Collecties", + "LabelSelectFolderGroups": "De inhoud van de volgende mappen automatisch groeperen in secties zoals Films, Muziek en TV:", + "LabelSelectFolderGroupsHelp": "Mappen die niet aangevinkt zijn worden getoond in hun eigen weergave.", + "Folders": "Mappen", + "DisplayInOtherHomeScreenSections": "In secties van het startscherm weergeven, zoals \"Recente Media\" en \"Verder Kijken\"", + "DisplayInMyMedia": "Op het startscherm weergeven", + "Shows": "Series", + "HeaderLibraryFolders": "Bibliotheek Mappen", + "HeaderTermsOfPurchase": "Aankoop Voorwaarden", + "PrivacyPolicy": "Privacy beleid", + "TermsOfUse": "Gebruiksvoorwaarden", + "RepeatMode": "Herhaal mode", + "RepeatOne": "E\u00e9n herhalen", + "RepeatAll": "Alle herhalen", + "LabelDefaultScreen": "Standaard scherm:", + "ConfirmEndPlayerSession": "Wilt u Emby afsluiten op {0}?", + "Yes": "Ja", + "No": "Nee", + "LiveTV": "Live TV", + "Schedule": "Schema", + "Recordings": "Opnames", + "MarkWatched": "Markeer als bekeken", + "ScanForNewAndUpdatedFiles": "Scan op nieuwe en bijgewerkte bestanden", + "DirectStreamHelp1": "De media is compatible met het apparaat wat betreft resolutie en media type (H.264, AC3 etc.), maar is in een incompatible bestandscontainer (.mkv, .avi, .wmv etc.). De video zal on the fly opnieuw worden verpakt voordat deze naar het apparaat wordt gestreamd.", + "DirectStreamHelp2": "Direct streamen van een bestand gebruikt weinig processor kracht zonder verlies van beeldkwaliteit.", + "MediaIsBeingConverted": "De media wordt geconverteerd naar een formaat dat compatible is met het apparaat dat wordt gebruikt om de media af te spelen.", + "StatsForNerds": "Statistieken voor nerds", + "LabelReasonForTranscoding": "Reden voor transcoderen:", + "DirectPlaying": "Direct afspelen", + "DirectStreaming": "Direct streamen", + "Transcoding": "Transcoderen", + "ContainerBitrateExceedsLimit": "Media bitrate overschrijdt limiet.", + "VideoCodecNotSupported": "Video codec niet ondersteund", + "AudioCodecNotSupported": "Audio codec niet ondersteund", + "SubtitleCodecNotSupported": "Ondertitel formaat niet ondersteund", + "DirectPlayError": "Direct Afspelen fout", + "ContainerNotSupported": "Container niet ondersteund", + "VideoLevelNotSupported": "Video niveau niet ondersteund", + "AudioBitrateNotSupported": "Audio bitrate niet ondersteund", + "AudioChannelsNotSupported": "Audio kanalen niet ondersteund", + "VideoResolutionNotSupported": "Video resolutie niet ondersteund", + "AudioProfileNotSupported": "Audio profiel niet ondersteund", + "AudioSampleRateNotSupported": "Audio sample rate niet ondersteund", + "AnamorphicVideoNotSupported": "Anamorfische video niet ondersteund", + "InterlacedVideoNotSupported": "Interlaced video niet ondersteund", + "SecondaryAudioNotSupported": "Switchen van audiotaal niet ondersteund", + "ErrorRemovingEmbyConnectAccount": "Er is een fout opgetreden bij het verwijderen van het Emby Connect acount. Zorg ervoor dat u een actieve internetverbinding heeft en probeer het opnieuw.", + "HeaderEmbyAccountRemoved": "Emby Account verwijderd", + "MessageEmbyAccontRemoved": "Het Emby account is van deze gebruiker verwijderd.", + "HeaderInvitationSent": "Uitnodiging Verzonden", + "MessageInvitationSentToUser": "Een email is verzonden naar {0} met een uitnodiging om uw uitnodiging te accepteren.", + "MessageInvitationSentToNewUser": "Een email is verzonden naar {0} met een uitnodiging om aan te melden bij Emby.", + "GuestUserNotFound": "Gebruiker is niet gevonden. Zorg ervoor dat de naam klopt en probeer het opnieuw, of probeer hun emailadres in te voeren.", + "ErrorReachingEmbyConnect": "Er is een fout opgetreden bij het bereiken van de Emby Connect server. Zorg ervoor dat u een actieve internetverbinding heeft en probeer het opnieuw.", + "ErrorAddingEmbyConnectAccount1": "Er was een probleem bij het toevoegen van het Emby Connect account. Hebt u een Emby account aangemaakt? U kunt u aanmelden op {0}.", + "ErrorAddingEmbyConnectAccount2": "Stuur een email naar {0} vanuit het email adres dat u voor uw Emby account gebruikt indien u nog steeds problemen heeft", + "ErrorAddingGuestAccount1": "Er was een probleem bij het toevoegen van het Emby Connect account. Heeft uw gast een Emby account aangemaakt? Zij kunnen zich aanmelden op {0}.", + "ErrorAddingGuestAccount2": "Stuur een email naar {0} met daarin uw email adres als die van hen indien u nog steeds problemen heeft.", + "MessageEmbyAccountAdded": "Het Emby account is aan deze gebruiker toegevoegd.", + "MessagePendingEmbyAccountAdded": "Het Emby account is aan de gebruiker toegevoegd. Er wordt een email verstuurd naar de eigenaar van het account. De uitnodiging zal moeten worden bevestigd door op de link in de email te klikken.", + "HeaderEmbyAccountAdded": "Emby Account Toegevoegd", + "LabelSubtitlePlaybackMode": "Ondertitel mode:", + "ErrorDeletingItem": "Er was een probleem bij het verwijderen van het item in Emby Server. Controleer dat Emby Server schrijfrechten op de map heeft en probeer het opnieuw.", + "NoSubtitles": "Geen ondertitels", + "Default": "Standaard", + "Absolute": "Absoluut", + "Smart": "Slim", + "Small": "Klein", + "Smaller": "Kleiner", + "Medium": "Gemiddeld", + "Large": "Groot", + "ExtraLarge": "Extra groot", + "OnlyForcedSubtitles": "Alleen geforceerde ondertitels", + "AlwaysPlaySubtitles": "Altijd ondertitels weergeven", + "DefaultSubtitlesHelp": "Ondertitels worden geladen op basis van de standaard en geforceerd markeringen in de ingesloten metadata. Indien meerdere opties aanwezig zijn zal rekening worden gehouden met de taalvoorkeuren.", + "SmartSubtitlesHelp": "Ondertitels worden weergegeven in de voorkeurstaal als de audio in een andere taal zijn.", + "HeaderSubtitleSettings": "Ondertitel Instellingen", + "HeaderSubtitleAppearance": "Ondertitel Weergave", + "OnlyForcedSubtitlesHelp": "Alleen als geforceerd gemarkeerde ondertitels worden geladen.", + "AlwaysPlaySubtitlesHelp": "Ondertitels die met de taalvoorkeur overeenkomen worden weergegeven, ongeacht de audiotaal.", + "NoSubtitlesHelp": "Ondertitels worden niet standaard weergegeven. Deze kunnen tijdens het afspelen handmatig worden ingeschakeld.", + "LabelPreferredSubtitleLanguage": "Voorkeurstaal ondertitels:", + "LabelTextSize": "Tekst grootte:", + "TheseSettingsAffectSubtitlesOnThisDevice": "Deze instellingen betreffen ondertitels op dit apparaat", + "LabelDropShadow": "Schaduw:", + "LabelTextBackgroundColor": "Tekst achtergrond kleur:", + "LabelWindowBackgroundColor": "Tekst achtergrond kleur:", + "LabelFont": "Lettertype:", + "LabelTextColor": "Tekst kleur:", + "Raised": "Verhoogd", + "Depressed": "Onderdrukt", + "Uniform": "Uniform", + "DropShadow": "Schaduw", + "SmallCaps": "Klein kapitaal", + "SubtitleAppearanceSettingsDisclaimer": "Deze instellingen hebben geen invloed op grafische ondertitels (PGS, DVD etc.) en ondertitels die hun eigen stijl ingebouwd hebben (ASS\/SSA).", + "LabelBurnSubtitles": "Ondertitels inbranden:", + "OnlyImageFormats": "Alleen image formaten (VOBSUP, PGS, SUB\/IDX etc.)", + "Normal": "Normaal", + "BurnSubtitlesHelp": "Bepaalt of de server ondertitels moet inbranden wanneer video's op basis van het ondertitel formaat geconverteerd moeten worden. Inbranden van ondertitels hebben een negatief effect op de server performance. Selecteer Automatisch om op afbeelding gebaseerde formaten (bijv. VOBSUB, PGS, SUB\/IDX etc.) en bepaalde ASS\/SSA ondertitels in te branden.", + "AllComplexFormats": "Alle complexe formaten (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Deze instellingen hebben ook effect op afspelen naar een Chromecast wanneer deze vanaf dit apparaat worden gestart.", + "HeaderWaitingForWifi": "Wachten op Wifi", + "WifiRequiredToDownload": "Wifi verbinding is vereist om te downloaden.", + "HeaderDownloadSettings": "Download Instellingen", + "Hide": "Verbergen", + "HeaderStartNow": "Nu Starten", + "HeaderNextVideoPlayingInValue": "Volgende Afgespeeld over {0}", + "HeaderNextEpisodePlayingInValue": "Volgende Aflevering over {0}", + "HeaderSecondsValue": "{0} Seconden", + "AudioBitDepthNotSupported": "Audio bit depth niet ondersteund", + "VideoProfileNotSupported": "Video profiel niet ondersteund", + "VideoFramerateNotSupported": "Video framerate niet ondersteund", + "VideoBitDepthNotSupported": "Video bit depth niet ondersteund", + "RefFramesNotSupported": "Aantal video reference frames niet ondersteund", + "ErrorConnectServerUnreachable": "Er was een probleem bij het uitvoeren van deze bewerking. Uw server kan de Emby Connect Server op {0} niet bereiken. Controleer dat uw server een actieve internetverbinding heeft en dat de communicatie toegestaan wordt door de firewall en\/of security software die u gebruikt.", + "StopRecording": "Stop opname", + "HeaderStopRecording": "Stop Opname", + "ManageRecording": "Beheren opnames", + "LabelDropImageHere": "Sleep de afbeelding hierheen of klik om te bladeren.", + "MessageFileReadError": "Er is een fout opgetreden bij het lezen van het bestand. Probeer het opnieuw.", + "Browse": "Bladeren", + "HeaderUploadImage": "Afbeelding Uploaden", + "HeaderAddUpdateImage": "Afbeelding Toevoegen\/Bijwerken", + "LabelImageType": "Afbeeldingstype:", + "Upload": "Uploaden", + "Primary": "Primair", + "Art": "Art", + "Backdrop": "Achtergrond", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (achterkant)", + "Disc": "Disk", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Schermafdruk", + "Thumb": "Miniatuur", + "ValueSeconds": "{0} seconden", + "HeaderAudioSettings": "Audio Instellingen", + "LabelAudioLanguagePreference": "Voorkeurs audiotaal:", + "LabelPlayDefaultAudioTrack": "Standaard audio spoor afspelen ongeacht de taal", + "HeaderVideoQuality": "Video Kwaliteit", + "CinemaModeConfigurationHelp": "Cinema mode brengt de theater ervaring naar uw woonkamer met de mogelijkheid om trailers en eigen intro's voor de film af te spelen.", + "EnableNextVideoInfoOverlay": "Toon informatie over de volgende video tijdens het afspelen", + "EnableNextVideoInfoOverlayHelp": "Toon informatie over de volgende video in de afspeellijst aan het einde van de video", + "PlayNextEpisodeAutomatically": "Speel volgende aflevering automatisch", + "LabelMaxChromecastBitrate": "Chromecast streaming kwaliteit:", + "LabelSkipBackLength": "Terugspoellengte", + "LabelSkipForwardLength": "Vooruitspoellengte", + "EnableCinemaMode": "Cinema Mode inschakelen", + "LabelInternetQuality": "Internet kwaliteit:", + "HeaderMusicQuality": "Muziek Kwaliteit", + "LabelHomeNetworkQuality": "Thuisnetwerk kwaliteit:", + "HeaderLatestMedia": "Nieuwste Media", + "HeaderRestartingEmbyServer": "Emby Server herstarten", + "RestartPleaseWaitMessage": "Wacht totdat Emby Server is afgesloten en opnieuw is gestart. Dit kan een paar minuten duren.", + "PlayNext": "Volgende afspelen", + "AllowSeasonalThemes": "Schakel seizoen thema's in", + "AllowSeasonalThemesHelp": "Indien ingeschakeld zullen seizoen thema's uw thema instellingen overschrijven.", + "AutoBasedOnLanguageSetting": "Automatisch (gebaseerd op taal instelling)", + "LabelDateTimeLocale": "Datum en tijd regio:", + "DirectorValue": "Regisseur: {0}", + "DirectorsValue": "Regisseurs: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Labels: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Ondertitels:", + "Off": "Uit", + "ShowTitle": "Toon titel", + "ShowYear": "Toon jaar", + "Filters": "Filters", + "Unplayed": "Niet afgespeeld", + "LabelTVHomeScreen": "TV mode begin scherm", + "Horizontal": "Horizontaal", + "Vertical": "Verticaal", + "GroupBySeries": "Groeperen op serie", + "HeaderVideoType": "Videotype", + "HeaderSeriesStatus": "Seriestatus", + "Features": "Kenmerken", + "Trailers": "Trailers", + "Extras": "Extra's", + "ThemeSongs": "Themamuziek", + "ThemeVideos": "Themavideo's", + "HeaderFavoriteMovies": "Favoriete films", + "HeaderFavoriteShows": "Favoriete series", + "HeaderFavoriteEpisodes": "Favoriete afleveringen", + "HeaderFavoriteVideos": "Favoriete video's", + "HeaderFavoriteGames": "Favoriete games", + "HeaderFavoriteArtists": "Favoriete artiesten", + "HeaderFavoriteAlbums": "Favoriete albums", + "HeaderFavoriteSongs": "Favoriete nummers", + "Ascending": "Oplopend", + "Descending": "Aflopend", + "ColorPrimaries": "Primaire kleuren", + "ColorSpace": "Kleurbereik", + "ColorTransfer": "Kleuroverdracht", + "VideoRange": "Videobereik", + "SeriesDisplayOrderHelp": "Afleveringen sorteren op uitzenddatum, DVD-volgorde, of absolute nummering.", + "PlaybackSettingsIntro": "Om de standaard afspeelinstellingen te configureren, stopt u het afspelen van de video. Vervolgens klikt u op het gebruikersicoon in de rechterbovenhoek van de app.", + "SubtitleSettingsIntro": "Om de standaard ondertiteling- en taalinstellingen te configureren, stopt u het afspelen van de video. Vervolgens klikt u op het gebruikersicoon in de rechterbovenhoek van de app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/pl.json b/src/bower_components/emby-webcomponents/strings/pl.json index 79d40c530a..2681bc36ac 100644 --- a/src/bower_components/emby-webcomponents/strings/pl.json +++ b/src/bower_components/emby-webcomponents/strings/pl.json @@ -1,685 +1,689 @@ { - "Absolute": "Bezwzględnie", - "Accept": "Akceptuj", - "AccessRestrictedTryAgainLater": "Dostęp jest aktualnie ograniczony. Spróbuj ponownie później.", - "Actor": "Aktor", - "Add": "Dodaj", - "AddToCollection": "Dodaj do kolekcji", - "AddToPlayQueue": "Dodaj do kolejki odtwarzania", - "AddToPlaylist": "Dodaj do listy", - "AddedOnValue": "Dodano {0}", - "Advanced": "Zaawansowane", - "AirDate": "Data emisji", - "Aired": "Premiera", - "Albums": "Albumy", - "All": "Wszystkie", - "AllChannels": "Wszystkie kanały", - "AllComplexFormats": "Wszystkie złożone formaty (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Wszystkie odcinki", - "AllLanguages": "Wszystkie języki", - "AllowSeasonalThemes": "Zezwalaj na automatyczne motywy sezonowe", - "AllowSeasonalThemesHelp": "Jeśli aktywne, motywy sezonowe będą sporadycznie nadpisywać Twoje ustawienia motywu.", - "AlwaysPlaySubtitles": "Zawsze wyświetlaj napisy", - "AlwaysPlaySubtitlesHelp": "Napisy pasujące do preferowanego języka będą wczytywane, niezależnie od języka ścieżki dźwiękowej.", - "AnamorphicVideoNotSupported": "Nieobsługiwane wideo anamorficzne", - "AndroidUnlockRestoreHelp": "W celu odzyskania poprzedniego zakupu, upewnij się, że zalogowałeś się na urządzeniu przy pomocy tego samego konta Google (lub Amazon), którym pierwotnie dokonałeś zakupu. Upewnij się, że sklep aplikacji działa poprawnie i nie jest ograniczony kontrolą rodzicielską, a Twoje połączenie z Internetem jest aktywne. Musisz to zrobić tylko raz, aby przywrócić poprzedni zakup.", - "AnyLanguage": "W dowolnym języku", - "Anytime": "O dowolnej porze", - "AroundTime": "Około {0}", - "Art": "Przezrocze", - "Artists": "Wykonawcy", - "AsManyAsPossible": "Tak wiele jak to możliwe", - "Ascending": "Rosnąco", - "AspectRatio": "Proporcje obrazu", - "AttemptingWakeServer": "Trwa próba wybudzenia serwera. Proszę czekać...", - "AttributeNew": "Nowy", - "AudioBitDepthNotSupported": "Nieobsługiwana głębia bitowa dźwięku", - "AudioBitrateNotSupported": "Nieobsługiwana przepływność dźwięku", - "AudioChannelsNotSupported": "Nieobsługiwany liczba kanałów dźwięku", - "AudioCodecNotSupported": "Nieobsługiwany kodek dźwięku", - "AudioProfileNotSupported": "Nieobsługiwany profil dźwięku", - "AudioSampleRateNotSupported": "Nieobsługiwana częstotliwość próbkowania dźwięku", - "Auto": "Automatycznie", - "AutoBasedOnLanguageSetting": "Automatyczna (w oparciu o ustawienia językowe)", - "AutomaticallyConvertNewContent": "Konwertuj automatycznie nowe media", - "AutomaticallyConvertNewContentHelp": "Nowe media dodane do tego folderu będą konwertowane automatycznie.", - "AutomaticallySyncNewContent": "Pobieraj nową zawartość automatycznie", - "AutomaticallySyncNewContentHelp": "Nowo dodana zawartość zostanie automatycznie pobrana na urządzenie.", - "Backdrop": "Fototapeta", - "Backdrops": "Fototapety", - "Banner": "Baner", - "BestFit": "Najlepsze dopasowane", - "BirthLocation": "Miejsce urodzin", - "Books": "Książki", - "Box": "Pudełko", - "BoxRear": "Pudełko (tył)", - "Browse": "Przeglądaj", - "BurnSubtitlesHelp": "Określa czy serwer powinien wypalać napisy podczas konwersji wideo, w zależności od formatu napisów. Unikanie wypalania napisów poprawia wydajność serwera. Wybierz Automatycznie, w celu wypalania zarówno napisów w formatach graficznych (np. VOBSUB, PGS, SUB/IDX, itp.), jak i pewnych napisów ASS/SSA.", - "ButtonCancel": "Anuluj", - "ButtonGotIt": "Rozumiem", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Odtwarzaj jedną minutę", - "ButtonRestart": "Uruchom ponownie", - "ButtonRestorePreviousPurchase": "Przywróć zakup", - "ButtonTryAgain": "Spróbuj ponownie", - "ButtonUnlockPrice": "Odblokuj {0}", - "ButtonUnlockWithPurchase": "Odblokuj zamawiając subskrypcję", - "CancelDownload": "Anuluj pobieranie", - "CancelRecording": "Anuluj nagranie", - "CancelSeries": "Anuluj nagrywanie serialu", - "Categories": "Kategorie", - "ChannelNameOnly": "Tylko kanał {0}", - "ChannelNumber": "Numer kanału", - "CinemaModeConfigurationHelp": "Tryb kinowy, wnosi kinowe doświadczenia wprost do Twojego salonu, z możliwością odtwarzania zwiastunów i niestandardowych prezentacji przez seansem.", - "CinemaModeFeatureDescription": "Tryb kinowy oferuje prawdziwie kinowe doświadczenia, z możliwością odtwarzania zwiastunów i niestandardowych prezentacji przed seansem.", - "CloudSyncFeatureDescription": "Umożliwia synchronizowanie mediów z chmurą, w celu łatwego wykonywania kopii zapasowej, archiwizacji i konwersji.", - "Collections": "Kolekcje", - "ColorPrimaries": "Wzorce kolorów", - "ColorSpace": "Przestrzeń kolorów", - "ColorTransfer": "Transfer kolorów", - "CommunityRating": "Ocena społeczności", - "Composer": "Kompozytor", - "ConfigureDateAdded": "Sposób ustalania daty dodania, można skonfigurować, w ustawieniach biblioteki, w kokpicie serwera Jellyfin.", - "ConfirmDeleteImage": "Usunąć obraz?", - "ConfirmDeleteItem": "Usunięcie tej pozycji usunie ją zarówno z systemu plików jak i z biblioteki mediów. Czy chcesz kontynuować?", - "ConfirmDeleteItems": "Usunięcie tej pozycji usunie ją zarówno z systemu plików jak i z biblioteki mediów. Czy chcesz kontynuować?", - "ConfirmDeletion": "Potwierdzenie usunięcia", - "ConfirmEndPlayerSession": "Czy chcesz zamknąć Jellyfin na {0}?", - "ConfirmRemoveDownload": "Usunąć pobraną pozycję?", - "Connect": "Połacz", - "ContainerBitrateExceedsLimit": "Przepływność mediów przekracza limit.", - "ContainerNotSupported": "Nieobsługiwany format kontenera", - "Continue": "Kontynuuj", - "ContinueInSecondsValue": "Kontynuuj za {0} sekund.", - "ContinueWatching": "Kontynuuj odtwarzanie", - "Continuing": "Dalej wyświetlane", - "Convert": "Konwertuj", - "ConvertItemLimitHelp": "Opcjonalne. Określa maksymalną liczbę konwertowanych pozycji.", - "ConvertUnwatchedVideosOnly": "Konwertuj tylko nieobejrzane", - "ConvertUnwatchedVideosOnlyHelp": "Tylko nieobejrzane wideo będą konwertowane.", - "ConvertingDots": "Trwa konwertowanie...", - "Countries": "Kraje", - "CriticRating": "Ocena krytyków", - "DateAdded": "Data dodania", - "DatePlayed": "Data odtwarzania", - "Days": "Dni", - "Default": "Domyślny", - "DefaultErrorMessage": "Wystąpił bląd podczas przetwarzania twojego rządania. Proszę spróbować ponownie poźniej.", - "DefaultSubtitlesHelp": "Napisy będą wczytywane w oparciu o znaczniki metadanych ścieżek dźwiękowych. Preferencje językowe brane są pod uwagę, gdy dostępnych jest wiele możliwości.", - "Delete": "Usuń", - "DeleteMedia": "Usuń pozycję", - "Depressed": "Wklęsły", - "Descending": "Malejąco", - "Desktop": "Komputer stacjonarny", - "DirectPlayError": "Nieudane odtwarzanie bezpośrednie", - "DirectPlaying": "Odtwarzanie bezpośrednie", - "DirectStreamHelp1": "Media są kompatybilne z urządzeniem w kwestii rozdzielczości i typu (H.264, AC3, etc), ale kontener pliku jest niekompatybilny (.mkv, .avi, .wmv, etc). Wideo zostanie przepakowane w locie przed rozpoczęciem transmisji do urządzenia.", - "DirectStreamHelp2": "Transmisja bezpośrednia pliku używa niewiele mocy przetwarzania, bez utraty jakości wideo.", - "DirectStreaming": "Transmisja bezpośrednia", - "Director": "Reżyser", - "DirectorValue": "Reżyser: {0}", - "DirectorsValue": "Reżyserzy: {0}", - "Disc": "Dysk", - "Disconnect": "Rozłącz", - "Dislike": "Nie lubię", - "Display": "Wyświetlanie", - "DisplayInMyMedia": "Wyświetlaj na ekranie startowym", - "DisplayInOtherHomeScreenSections": "Wyświetlaj na ekranie startowym sekcje Ostatnio dodane i Kontynuuj odtwarzanie", - "DisplayMissingEpisodesWithinSeasons": "Wyświetlaj w sezonach brakujące odcinki", - "DisplayMissingEpisodesWithinSeasonsHelp": "Ta opcja, musi zostać dodatkowo aktywowana w bibliotece seriali, w konfiguracji serwera Jellyfin.", - "DisplayModeHelp": "Określa typ urządzenia, na którym uruchomiono Jellyfin.", - "DoNotRecord": "Nie nagrywaj", - "Down": "W dół", - "Download": "Pobierz", - "DownloadItemLimitHelp": "Opcjonalne. Określa maksymalną liczbę pobieranych pozycji.", - "Downloaded": "Pobrano", - "Downloading": "Pobieranie", - "DownloadingDots": "Trwa pobieranie...", - "Downloads": "Pobrane", - "DownloadsValue": "{0} pobrań", - "DropShadow": "Rozproszony", - "DvrFeatureDescription": "Zaplanuj pojedyncze nagrania programów telewizyjnych, nagrywanie seriali i więcej za pomocą nagrywarki Jellyfin.", - "DvrSubscriptionRequired": "Funkcja nagrywarki wymaga aktywnej subskrypcji Jellyfin Premium.", - "Edit": "Edycja", - "EditImages": "Edytuj obrazy", - "EditMetadata": "Edytuj metadane", - "EditSubtitles": "Edytuj napisy", - "EnableBackdrops": "Wyświetlaj fototapety", - "EnableBackdropsHelp": "Umożliwia wyświetlanie fototapet, w tle niektórych stron, podczas przeglądania biblioteki.", - "EnableCinemaMode": "Włącz tryb kinowy", - "EnableColorCodedBackgrounds": "Aktywuj kolorowe tła bazujące na zawartości", - "EnableDisplayMirroring": "Aktywuj wyświetlanie lustrzane", - "EnableExternalVideoPlayers": "Aktywuj obsługę zewnętrznych odtwarzaczy", - "EnableExternalVideoPlayersHelp": "Menu wyboru zewnętrznego odtwarzacza będzie wyświetlane przed rozpoczęciem odtwarzania wideo.", - "EnableNextVideoInfoOverlay": "Pokazuj następne wideo podczas odtwarzania", - "EnableNextVideoInfoOverlayHelp": "Umożliwia wyświetlanie pod koniec odtwarzania wideo, informacji o następnym wideo na liście odtwarzania.", - "EnableThemeSongs": "Odtwarzaj motywy muzyczne", - "EnableThemeSongsHelp": "Umożliwia odtwarzanie motywów muzycznych podczas przeglądania biblioteki.", - "EnableThemeVideos": "Odtwarzaj motywy wideo", - "EnableThemeVideosHelp": "Umożliwia wyświetlanie motywów wideo podczas przeglądania biblioteki,", - "Ended": "Zakończony", - "EndsAtValue": "Koniec o {0}", - "Episodes": "Odcinki", - "Error": "Błąd", - "ErrorAddingGuestAccount1": "Podczas dodawania konta Jellyfin Connect wystąpił błąd. Czy użytkownik gościnny utworzył konto Jellyfin? Użytkownicy gościnni mogą się zarejestrować na stronie {0}.", - "ErrorAddingGuestAccount2": "Jeśli ciągle masz problem, wyślij wiadomości na adres {0}, podając swój adres pocztowy oraz swoich użytykowników.", - "ErrorAddingJellyfinConnectAccount1": "Podczas dodawania konta Jellyfin Connect wystąpił błąd. Czy utworzyłeś wcześniej konto Jellyfin?. Zarejestruj się na {0}.", - "ErrorAddingJellyfinConnectAccount2": "Jeśli ciągle masz problem, wyślij wiadomości na adres {0}, z adresu pocztowego skojarzonego z kontem Jellyfin.", - "ErrorConnectServerUnreachable": "Podczas wykonywania żądanej operacji wystąpił błąd. Połączenie z Twojego serwera z serwerem Jellyfin Connect z {0} było niemożliwe. Upewnij się, że połączenie internetowe na Twoim serwerze jest aktywne i komunikacja jest dozwolona przez zaporę sieciową i zainstalowane oprogramowanie antywirusowe.", - "ErrorDeletingItem": "Podczas usuwania pozycji z serwera Jellyfin wystąpił błąd. Upewnij się, że serwer ma uprawnienia do zapisu w folderze mediów i spróbuj ponownie.", - "ErrorReachingJellyfinConnect": "Podczas próby połączenia z serwerem Jellyfin Connect wystąpił błąd. Upewnij się, że połączenie internetowe jest aktywne i spróbuj ponownie.", - "ErrorRemovingJellyfinConnectAccount": "Podczas usuwania konta Jellyfin Connect wystąpił błąd. Upewnij się, że połączenie internetowe jest aktywne i spróbuj ponownie.", - "ExtraLarge": "Wielki", - "Extras": "Materiały dodatkowe", - "Favorite": "Ulubione", - "Favorites": "Ulubione", - "FeatureRequiresJellyfinPremiere": "Ta funkcja wymaga aktywnej subskrypcji Jellyfin Premium.", - "Features": "Funkcje", - "File": "Plik", - "Fill": "Rozciągnij", - "Filters": "Filtry", - "Folders": "Foldery", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Korzystaj z darmowego dostępu do aplikacji Jellyfin na swoich urządzeniach.", - "Friday": "Piątek", - "GenreValue": "Gatunek: {0}", - "Genres": "Gatunki", - "GenresValue": "Gatunki: {0}", - "GroupBySeries": "Grupuj po serialach", - "GroupVersions": "Wersje grup", - "GuestStar": "Gość specjalny", - "GuestUserNotFound": "Użytkownik nie istnieje. Upewnij się, że nazwa jest poprawna lub spróbuj wprowadzając adres pocztowy.", - "Guide": "Przewodnik", - "HDPrograms": "Programy w jakości HD", - "HeaderActiveRecordings": "Nagrania aktywne", - "HeaderAddToCollection": "Dodaj do kolekcji", - "HeaderAddToPlaylist": "Dodaj do listy", - "HeaderAddUpdateImage": "Dodaj / Aktualizuj obraz", - "HeaderAlbumArtists": "Wykonawcy albumów", - "HeaderAlreadyPaid": "Już opłacone?", - "HeaderAppearsOn": "Występuje", - "HeaderAudioBooks": "Książka mówiona", - "HeaderAudioSettings": "Ustawienia dźwięku", - "HeaderBecomeProjectSupporter": "Zamów subskrypcję Premium", - "HeaderBenefitsJellyfinPremiere": "Korzyści z subskrypcji Premium", - "HeaderCancelRecording": "Anuluj nagranie", - "HeaderCancelSeries": "Anuluj nagrywanie serialu", - "HeaderCinemaMode": "Tryb kinowy", - "HeaderCloudSync": "Synchronizacja chmurowa", - "HeaderConfirmRecordingCancellation": "Potwierdź Anulowanie Nagrania", - "HeaderContinueListening": "Kontynuuj słuchanie", - "HeaderContinueWatching": "Kontynuuj odtwarzanie", - "HeaderConvertYourRecordings": "Konwertuj nagrania", - "HeaderCustomizeHomeScreen": "Dostosuj ekran startowy", - "HeaderDeleteItem": "Usuń pozycję", - "HeaderDeleteItems": "Usuń pliki", - "HeaderDisplaySettings": "Ustawienia wyświetlania", - "HeaderDownloadSettings": "Ustawienia pobierania", - "HeaderEditImages": "Edytuj obrazy", - "HeaderEnabledFields": "Pola aktywne", - "HeaderEnabledFieldsHelp": "Odznacz pole, aby je zablokować i zapobiec zmianom danych w przyszłości.", - "HeaderExternalIds": "Identyfikatory zewnętrzne:", - "HeaderFavoriteAlbums": "Albumy ulubione", - "HeaderFavoriteArtists": "Wykonawcy ulubieni", - "HeaderFavoriteCollections": "Kolekcje ulubione", - "HeaderFavoriteEpisodes": "Odcinki ulubione", - "HeaderFavoriteGames": "Gry ulubione", - "HeaderFavoriteMovies": "Filmy ulubione", - "HeaderFavoritePlaylists": "Listy ulubione", - "HeaderFavoriteShows": "Seriale ulubione", - "HeaderFavoriteSongs": "Utwory ulubione", - "HeaderFavoriteVideos": "Wideo ulubione", - "HeaderFreeApps": "Darmowe aplikacje Jellyfin", - "HeaderHomeScreen": "Ekran startowy", - "HeaderIdentifyItemHelp": "Wpisz kryteria wyszukiwania. Zmniejszając ilość kryteriów zwiększysz ilość wyników.", - "HeaderInvitationSent": "Wysłano zaproszenie", - "HeaderJellyfinAccountAdded": "Dodano konto Jellyfin", - "HeaderJellyfinAccountRemoved": "Usunięto konto Jellyfin", - "HeaderKeepRecording": "Zachowaj nagranie", - "HeaderKeepSeries": "Zachowaj nagranie serialu", - "HeaderLatestChannelItems": "Kanały ostatnio odtwarzane", - "HeaderLatestChannelMedia": "Kanały ostatnio dodane", - "HeaderLatestFrom": "{0} ostatnio dodane", - "HeaderLatestMedia": "Media ostatnio dodane", - "HeaderLatestRecordings": "Nagrania ostatnio dodane", - "HeaderLearnMore": "Dowiedz się więcej", - "HeaderLibraryFolders": "Foldery biblioteki", - "HeaderLibraryOrder": "Kolejność biblioteki", - "HeaderMetadataSettings": "Ustawienia metadanych", - "HeaderMusicQuality": "Jakość muzyki", - "HeaderMyDevice": "Moje urządzenie", - "HeaderMyDownloads": "Moje pobrania", - "HeaderMyMedia": "Moje media", - "HeaderMyMediaSmall": "Moje media (małe)", - "HeaderNewRecording": "Nowe nagranie", - "HeaderNextEpisodePlayingInValue": "Następne odcinek za {0}", - "HeaderNextUp": "Do obejrzenia", - "HeaderNextVideoPlayingInValue": "Następne wideo za {0}", - "HeaderOfflineDownloads": "Media dostępne lokalnie", - "HeaderOfflineDownloadsDescription": "Umożliwia pobieranie mediów na urządzenia klienckie, aby z nich korzystać bez konieczności połączenia z serwerem.", - "HeaderOnNow": "Teraz", - "HeaderPhotoAlbums": "Albumy fotografii", - "HeaderPlayMyMedia": "Odtwarzaj pozycję", - "HeaderPlayOn": "Odtwarzaj na", - "HeaderPlaybackError": "Błąd Odtwarzania", - "HeaderRecordingOptions": "Opcje nagrywania", - "HeaderRemoteControl": "Zdalne sterowanie", - "HeaderRestartingJellyfinServer": "Trwa ponownie uruchomienie serwera Jellyfin", - "HeaderSaySomethingLike": "Powiedz coś jak...", - "HeaderSecondsValue": "{0} sekund", - "HeaderSelectDate": "Wybierz datę", - "HeaderSeriesOptions": "Opcje nagrywania serialu", - "HeaderSeriesStatus": "Stan serialu", - "HeaderSpecialEpisodeInfo": "Specjalne informacje o odcinku", - "HeaderStartNow": "Rozpocznij teraz", - "HeaderStopRecording": "Zatrzymaj nagrywanie", - "HeaderSubtitleAppearance": "Wygląd napisów", - "HeaderSubtitleSettings": "Ustawienia napisów", - "HeaderSyncRequiresSub": "Pobieranie wymaga aktywnej subskrypcji Jellyfin Premium.", - "HeaderTermsOfPurchase": "Zasady zakupu", - "HeaderTryPlayback": "Wypróbuj odtwarzanie", - "HeaderUnlockFeature": "Odblokuj funkcję", - "HeaderUploadImage": "Przekaż obraz", - "HeaderVideoQuality": "Jakość wideo", - "HeaderVideoType": "Typ wideo", - "HeaderWaitingForWifi": "Oczekiwanie na sieć WiFi", - "HeaderWakeServer": "Wybudzaj serwer", - "HeaderYouSaid": "Powiedziałeś...", - "Help": "Pomoc", - "Hide": "Ukryj", - "HideWatchedContentFromLatestMedia": "Ukrywaj obejrzaną zawartość na listach ostatnio dodanych", - "Home": "Start", - "Horizontal": "Horyzontalny", - "HowDidYouPay": "W jaki sposób zapłaciłeś?", - "IHaveJellyfinPremiere": "Posiadam subskrypcję Jellyfin Premium", - "IPurchasedThisApp": "Kupiłem tę aplikację", - "Identify": "Identyfikuj", - "Images": "Obrazy", - "ImdbRating": "Ocena IMDb", - "InstallingPackage": "Instalowanie {0}", - "InstantMix": "Szybki remiks", - "InterlacedVideoNotSupported": "Nieobsługiwane wideo z przeplotem", - "ItemCount": "{0} pozycje", - "Items": "Pozycje", - "KeepDownload": "Zachowaj pobraną pozycję", - "KeepOnDevice": "Zachowaj na urządzeniu", - "Kids": "Dla dzieci", - "Label3DFormat": "Format 3D:", - "LabelAirDays": "Dni transmisji:", - "LabelAirTime": "Czas transmisji:", - "LabelAirsAfterSeason": "Emisja po sezonie:", - "LabelAirsBeforeEpisode": "Emisja przed odcinkiem:", - "LabelAirsBeforeSeason": "Emisja przed sezonem:", - "LabelAlbum": "Album", - "LabelAlbumArtists": "Wykonawcy albumów", - "LabelArtists": "Wykonawcy:", - "LabelArtistsHelp": "Oddzielaj używając ;", - "LabelAudio": "Dźwięk:", - "LabelAudioLanguagePreference": "Preferowany język ścieżki dźwiękowej", - "LabelBirthDate": "Data urodzenia:", - "LabelBirthYear": "Rok urodzenia:", - "LabelBitrateMbps": "Przepływność (Mbps):", - "LabelBurnSubtitles": "Wypalaj napisy:", - "LabelChannels": "Kanały:", - "LabelCollection": "Kolekcja:", - "LabelCommunityRating": "Ocena społeczności:", - "LabelContentType": "Typ zawartości", - "LabelConvertTo": "Konwertuj do:", - "LabelCountry": "Kraj:", - "LabelCriticRating": "Ocena krytyków:", - "LabelCustomRating": "Kategoria wiekowa własna:", - "LabelDashboardTheme": "Motyw kokpitu serwera:", - "LabelDateAdded": "Data dodania:", - "LabelDateTimeLocale": "Strefa czasowa:", - "LabelDeathDate": "Data śmierci:", - "LabelDefaultScreen": "Ekran domyślny:", - "LabelDiscNumber": "Numer dysku:", - "LabelDisplayLanguage": "Język interfejsu:", - "LabelDisplayLanguageHelp": "Tłumaczenie Jellyfin to projekt, który ciągle trwa.", - "LabelDisplayMode": "Tryb wyświetlania:", - "LabelDisplayOrder": "Kolejność wyświetlania:", - "LabelDropImageHere": "Upuść obraz tutaj lub naciśnij przycisk, aby przeglądać.", - "LabelDropShadow": "Cień:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "Adres pocztowy:", - "LabelEndDate": "Data zakończenia:", - "LabelEpisodeNumber": "Numer odcinka:", - "LabelFont": "Czcionka:", - "LabelHomeNetworkQuality": "Jakość dla sieci lokalnej:", - "LabelHomeScreenSectionValue": "Sekcja ekranu startowego {0}:", - "LabelImageType": "Typ obrazu:", - "LabelInternetQuality": "Jakość dla sieci internetowej:", - "LabelItemLimit": "Limit pozycji:", - "LabelKeep:": "Zachowuj:", - "LabelKeepUpTo": "Zachowuj do:", - "LabelLanguage": "Język:", - "LabelLockItemToPreventChanges": "Zablokuj tę pozycję, aby zapobiec przyszłym zmianom", - "LabelMaxChromecastBitrate": "Jakość transmisji Chromecast:", - "LabelMetadataDownloadLanguage": "Preferowany język pobierania:", - "LabelName": "Nazwa:", - "LabelNumber": "Numer:", - "LabelOriginalAspectRatio": "Oryginalny format obrazu:", - "LabelOriginalTitle": "Tytuł oryginalny:", - "LabelOverview": "Opis:", - "LabelParentNumber": "Numer nadrzędny:", - "LabelParentalRating": "Kategoria wiekowa:", - "LabelPath": "Folder:", - "LabelPersonRole": "Rola:", - "LabelPersonRoleHelp": "Przykład: kierowca ciężarówki z lodami", - "LabelPlaceOfBirth": "Miejsce urodzenia:", - "LabelPlayDefaultAudioTrack": "Odtwarzaj domyślną ścieżkę dźwiękową niezależnie od języka", - "LabelPlaylist": "Lista odtwarzania:", - "LabelPreferredSubtitleLanguage": "Preferowany język napisów:", - "LabelProfile": "Profil:", - "LabelQuality": "Jakość:", - "LabelReasonForTranscoding": "Powód transkodowania", - "LabelRecord": "Nagraj:", - "LabelRefreshMode": "Tryb odświeżania:", - "LabelReleaseDate": "Data wydania:", - "LabelRuntimeMinutes": "Czas (w minutach):", - "LabelScreensaver": "Wygaszacz ekranu:", - "LabelSeasonNumber": "Numer sezonu:", - "LabelSelectFolderGroups": "Grupuj zawartość z następujących folderów w widokach taki, jak Filmy, Muzyka i Seriale:", - "LabelSelectFolderGroupsHelp": "Foldery, które nie zostały zaznaczone, będą wyświetlane w swoich własnych, osobnych widokach.", - "LabelShortOverview": "Streszczenie:", - "LabelSkin": "Skóra:", - "LabelSkipBackLength": "Długość skoku wstecz:", - "LabelSkipForwardLength": "Długość skoku wprzód:", - "LabelSortBy": "Sortuj po:", - "LabelSortOrder": "Porządek sortowania", - "LabelSortTitle": "Tytuł sortowania:", - "LabelSoundEffects": "Efekty dźwiękowe", - "LabelSource": "Źródło:", - "LabelStartWhenPossible": "Zaczynaj kiedy możliwe:", - "LabelStatus": "Stan:", - "LabelStopWhenPossible": "Zatrzymuj kiedy możliwe:", - "LabelSubtitlePlaybackMode": "Tryb napisów:", - "LabelSubtitles": "Napisy:", - "LabelSyncJobName": "Nazwa zadania:", - "LabelSyncNoTargetsHelp": "Wygląda na to, że nie posiadasz żadnych aplikacji obsługujących pobrane media.", - "LabelSyncTo": "Synchronizuj z:", - "LabelTVHomeScreen": "Ekran startowy trybu telewizyjnego:", - "LabelTagline": "Motto:", - "LabelTextBackgroundColor": "Kolor tła tekstu:", - "LabelTextColor": "Kolor tekstu:", - "LabelTextSize": "Rozmiar tekstu:", - "LabelTheme": "Motyw:", - "LabelTitle": "Tytuł:", - "LabelTrackNumber": "Numer utworu:", - "LabelType": "Typ:", - "LabelVersion": "Wersja:", - "LabelVideo": "Wideo:", - "LabelWebsite": "Strona internetowa", - "LabelWindowBackgroundColor": "Kolor tła tekstu:", - "LabelYear": "Rok:", - "Large": "Duży", - "LatestFromLibrary": "{0} ostatnio dodane", - "LearnHowYouCanContribute": "Dowiedz się jak możesz pomóc.", - "LearnMore": "Dowiedz się więcej", - "Like": "Lubię", - "LinksValue": "Łącza: {0}", - "List": "Lista", - "Live": "Na żywo", - "LiveBroadcasts": "Transmisje na żywo", - "LiveTV": "Telewizja", - "LiveTvFeatureDescription": "Oglądaj transmisje telewizyjne z dowolną aplikacją Jellyfin, za pomocą zainstalowanego na serwerze Jellyfin tunera telewizyjnego.", - "LiveTvRequiresUnlock": "Odbiór transmisji telewizyjnych wymaga aktywnej subskrypcji Jellyfin Premiere.", - "Logo": "Logo", - "ManageRecording": "Zarządzaj nagrywaniem", - "MarkPlayed": "Oznacz jako obejrzane", - "MarkUnplayed": "Oznacz jako nieobejrzane", - "MarkWatched": "Oznacz jako obejrzane", - "MediaIsBeingConverted": "Media będą konwertowane do formatu kompatybilnego z urządzeniem, na który będą odtwarzane.", - "Medium": "Średni", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Funkcja automatycznego nagrywania seriali wymaga aktywnej subskrypcji Jellyfin Premium.", - "MessageAreYouSureDeleteSubtitles": "Czy jesteś pewien, że chcesz usunąć ten plik z napisami?", - "MessageConfirmRecordingCancellation": "Anulować nagranie?", - "MessageDownloadQueued": "Dodano do kolejki pobierania.", - "MessageFileReadError": "Podczas wczytywania plików wystąpił błąd. Spróbuj ponownie później.", - "MessageIfYouBlockedVoice": "Jeśli odmówisz aplikacji dostępu głosowego, będziesz musiał zmienić konfigurację przed ponownym urządzeniem.", - "MessageInvitationSentToNewUser": "Wiadomość pocztowa, z prośbą o rejestrację konta Jellyfin, została wysłana do {0}.", - "MessageInvitationSentToUser": "Wiadomość pocztowa, z prośbą o akceptację zaproszenia współużytkowania, została wysłana do {0}.", - "MessageItemSaved": "Obiekt zapisany.", - "MessageItemsAdded": "Dodano pozycję.", - "MessageJellyfinAccontRemoved": "Konto Jellyfin zostało usunięte dla tego użytkownika.", - "MessageJellyfinAccountAdded": "Konto Jellyfin zostało dodane do użytkownika.", - "MessageLeaveEmptyToInherit": "Zostaw puste aby odziedziczyć ustawienia z nadrzędnej pozycji, lub globalnej wartości domyślnej.", - "MessageNoDownloadsFound": "Brak dostępnych lokalnie mediów. Pobierz media do użycia lokalnie, używając przycisku Pobierz, dostępnego w aplikacji.", - "MessageNoServersAvailableToConnect": "Brak serwerów dostępnych do połączenia. Jeśli zostałeś zaproszony do korzystania z serwera, upewnij się, że je zaakceptowałeś poniżej lub za naciskając na łącze w wiadomości pocztowej.", - "MessageNoSyncJobsFound": "Brak pobieranych plików. Utwórz zadanie pobierania, używając przycisku Pobierz, dostępnego w aplikacji.", - "MessagePendingJellyfinAccountAdded": "Konto Jellyfin zostało połączone z tym użytkownikiem. Wiadomość pocztowa została wysłana do właściciela tego konta. Wymagane będzie potwierdzenie zaproszenia, poprzez naciśnięcie na łącze umieszczone w wiadomości.", - "MessagePlayAccessRestricted": "Odtwarzanie tej zawartości jest aktualnie ograniczone. Skontaktuj się z administratorem serwera, aby uzyskać dodatkowe informacje.", - "MessageToValidateSupporter": "Jeśli posiadasz aktywną subskrypcję Jellyfin Premium, upewnij się, że ją poprawnie skonfigurowałeś przy pomocy Kokpitu serwera Jellyfin, do którego możesz uzyskać dostęp, klikając na pozycję Premium menu startowego.", - "MessageUnlockAppWithPurchaseOrSupporter": "Odblokuj tę funkcję, za niewielką jednorazową opłatą lub przy użyciu aktywnej subskrypcji Jellyfin Premium.", - "MessageUnlockAppWithSupporter": "Odblokuj tę funkcję przy użyciu subskrypcji Jellyfin Premium.", - "MessageWeDidntRecognizeCommand": "Przepraszamy, nie rozpoznaliśmy tej komendy.", - "MinutesAfter": "minut po", - "MinutesBefore": "minut przed", - "Mobile": "Telefon / tabet", - "Monday": "Poniedziałek", - "More": "Więcej", - "MoveLeft": "Przesuń w lewo", - "MoveRight": "Przesuń w prawo", - "Movies": "Filmy", - "MySubtitles": "Moje napisy", - "Name": "Nazwa", - "NewCollection": "Nowa kolekcja", - "NewCollectionHelp": "Kolekcje umożliwiają spersonalizowane grupowanie filmów i innej zawartości biblioteki.", - "NewCollectionNameExample": "Przykład: Kolekcja Star Wars", - "NewEpisodes": "Nowe odcinki", - "NewEpisodesOnly": "Tylko nowe odcinki", - "News": "Wiadomości", - "Next": "Następny", - "No": "Nie", - "NoItemsFound": "Brak dostępnych pozycji.", - "NoSubtitleSearchResultsFound": "Brak wyników wyszukiwania.", - "NoSubtitles": "Brak napisów", - "NoSubtitlesHelp": "Domyślnie napisy nie będą wczytywane. Można je ciągle włączyć ręcznie podczas odtwarzania.", - "None": "Brak", - "Normal": "Normalny", - "Off": "Wyłączone", - "OneChannel": "Jeden kanał", - "OnlyForcedSubtitles": "Tylko wymuszone napisy", - "OnlyForcedSubtitlesHelp": "Tylko napisy oznaczone jako wymuszone będą wczytywane.", - "OnlyImageFormats": "Tylko formaty graficzne (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Otwórz", - "OptionNew": "Nowa...", - "Original": "Orignalne", - "OriginalAirDateValue": "Data pierwszej emisji: {0}", - "Overview": "Opis", - "PackageInstallCancelled": "Instalacja {0} anulowana.", - "PackageInstallCompleted": "Instalacja {0} zakończona.", - "PackageInstallFailed": "Instalacja {0} nieudana.", - "ParentalRating": "Kategoria wiekowa", - "People": "Osoby", - "PerfectMatch": "Perfekcyjne dopasowanie", - "Photos": "Fotografie", - "PlaceFavoriteChannelsAtBeginning": "Umieszczaj ulubione kanały na początku", - "Play": "Odtwarzaj", - "PlayAllFromHere": "Odtwarzaj wszystko z tej lokalizacji", - "PlayCount": "Liczba odtworzeń", - "PlayFromBeginning": "Odtwarzaj od początku", - "PlayNext": "Odtwarzaj następne", - "PlayNextEpisodeAutomatically": "Odtwarzaj następny odcinek automatycznie", - "PlaybackErrorNoCompatibleStream": "Brak kompatybilnych transmisji. Spróbuj ponownie później lub skontaktuj się z administratorem serwera, aby uzyskać dodatkowe informacje.", - "PlaybackErrorNotAllowed": "Brak uprawnień do odtwarzania tej zawartości. Skontaktuj się z administratorem serwera, aby uzyskać dodatkowe informacje.", - "PlaybackErrorPlaceHolder": "Proszę włożyć dysk, aby odtwarzać to wideo.", - "PlaybackSettings": "Ustawienia odtwarzania", - "PlaybackSettingsIntro": "W celu skonfigurowania domyślnych ustawień odtwarzania, zatrzymaj odtwarzanie, a następnie naciśnij ikonę użytkownika w górnej prawej sekcji aplikacji.", - "Played": "Odtworzone", - "Playlists": "Listy", - "PleaseEnterNameOrId": "Proszę wprowadź nazwę lub zewnętrzne Id.", - "PleaseRestartServerName": "Proszę ponownie uruchomić serwer Jellyfin - {0}", - "PleaseSelectDeviceToSyncTo": "Wybierz urządzenie, na które chcesz pobrać.", - "PleaseSelectTwoItems": "Proszę wybierz przynajmniej dwie pozycje.", - "Premiere": "Premiera", - "Premieres": "Premiery", - "Previous": "Poprzedni", - "Primary": "Podstawowy", - "PrivacyPolicy": "Polityka prywatności", - "Producer": "Producent", - "ProductionLocations": "Kraje", - "Programs": "Programy", - "PromoConvertRecordingsToStreamingFormat": "Jellyfin Premier umożliwia automatyczną konwersję nagrań do formatu przyjaznego transmisjom. Nagrania będą konwertowane w flocie do kontenera MP4 lub MKV, w zależności o konfiguracji serwera Jellyfin.", - "Quality": "Jakość", - "QueueAllFromHere": "Kolejkuj wszystko z tej lokalizacji", - "Raised": "Wypukły", - "RecentlyWatched": "Ostatnio obejrzane", - "Record": "Nagrywaj", - "RecordSeries": "Nagraj seryjnie", - "RecordingCancelled": "Anulowano nagranie.", - "RecordingScheduled": "Zaplanowano nagranie.", - "Recordings": "Nagrania", - "RefFramesNotSupported": "Nieobsługiwana liczba klatek referencyjnych wideo", - "Refresh": "Odśwież", - "RefreshDialogHelp": "Metadane są odświeżane w oparciu o ustawienia i dostawców internetowych, aktywowanych w kokpicie serwera Jellyfin.", - "RefreshMetadata": "Odśwież metadane", - "RefreshQueued": "Odświeżanie dodane do kolejki zadań.", - "Reject": "Odrzuć", - "ReleaseDate": "Data wydania", - "RemoveDownload": "Usuń pobraną pozycję", - "RemoveFromCollection": "Usuń z kolekcji", - "RemoveFromPlaylist": "Usuń z listy", - "RemovingFromDevice": "Usuń z urządzenia", - "Repeat": "Powtórz", - "RepeatAll": "Powtarzaj wszystko", - "RepeatEpisodes": "Powtarzaj odcinki", - "RepeatMode": "Tryb powtarzania", - "RepeatOne": "Powtarzaj jedno", - "ReplaceAllMetadata": "Zastępuj wszystkie metadane", - "ReplaceExistingImages": "Zastępuj istniejące obrazy", - "RestartPleaseWaitMessage": "Czekaj na zamknięcie i ponowne uruchomienie serwera Jellyfin. To może trwać ok. jednej, dwóch minut.", - "ResumeAt": "Wznów odtwarzanie od {0}", - "Retry": "Ponów", - "RunAtStartup": "Uruchamiaj po starcie", - "Runtime": "Czas trwania", - "Saturday": "Sobota", - "Save": "Zapisz", - "ScanForNewAndUpdatedFiles": "Skanuj w poszukiwaniu nowych lub zaktualizowanych plików", - "Schedule": "Zaplanuj", - "Screenshot": "Zrzut ekranu", - "Screenshots": "Zrzuty ekranu", - "Search": "Szukaj", - "SearchForCollectionInternetMetadata": "Wyszukuj grafiki i metadane w Internecie", - "SearchForMissingMetadata": "Wyszukuj brakujące metadane", - "SearchForSubtitles": "Wyszukuj napisy", - "SearchResults": "Wyniki wyszukiwania", - "SecondaryAudioNotSupported": "Nieobsługiwane przełączanie ścieżek dźwiękowych", - "SeriesCancelled": "Anulowano nagranie seryjne.", - "SeriesDisplayOrderHelp": "Sortuje odcinki po dacie emisji, kolejności na DVD lub bezwzględnej numeracji.", - "SeriesRecordingScheduled": "Zaplanowano nagranie seryjne.", - "SeriesSettings": "Ustawienia nagrywania serialu", - "SeriesYearToPresent": "{0} - Teraz", - "ServerNameIsRestarting": "Jellyfin Server - {0} jest uruchamiany ponownie.", - "ServerNameIsShuttingDown": "Serwer Jellyfin - {0} jest zamykany.", - "ServerUpdateNeeded": "Ten serwer Jellyfin wymaga aktualizacji. Odwiedź stronę {0}, aby pobrać najnowszą wersję.", - "Settings": "Ustawienia", - "SettingsSaved": "Zapisano ustawienia", - "Share": "Udostępnij", - "ShowIndicatorsFor": "Pokazuj wskaźniki dla:", - "ShowTitle": "Pokazuj tytuł", - "ShowYear": "Pokazuj rok", - "Shows": "Seriale", - "Shuffle": "Wylosuj", - "SkipEpisodesAlreadyInMyLibrary": "Pomijaj nagrywanie odcinków, które już są w bibliotece", - "SkipEpisodesAlreadyInMyLibraryHelp": "Odcinki będą porównywane przy pomocy numeru sezonu i odcinka, jeśli są dostępne.", - "Small": "Mały", - "SmallCaps": "Kapitaliki", - "Smaller": "Mniejsze", - "Smart": "Inteligentny", - "SmartSubtitlesHelp": "W przypadku, gdy ścieżka dźwiękowa jest w języku obcym, zostaną wczytane napisy w preferowanym języku.", - "Songs": "Utwory", - "Sort": "Sortuj", - "SortByValue": "Sortowanie wg {0}", - "SortChannelsBy": "Sortuj kanały wg:", - "SortName": "Tytuł sortowania", - "Sports": "Wydarzenia sportowe", - "StatsForNerds": "Statystyki dla maniaków", - "StopRecording": "Zatrzymaj nagrywanie", - "Studios": "Wytwórnie", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Powyższe ustawienia dotyczą także odtwarzania Chromecast rozpoczętego przez to urządzenie.", - "SubtitleAppearanceSettingsDisclaimer": "Te ustawienia nie mają zastosowania do napisów graficznych (PGS, DVD, etc) lub napisów, które posiadają swoje własne wbudowane style (ASS/SSA).", - "SubtitleCodecNotSupported": "Nieobsługiwany format napisów", - "SubtitleSettings": "Ustawienia napisów", - "SubtitleSettingsIntro": "W celu skonfigurowania domyślnych ustawień napisów i języka, zatrzymaj odtwarzanie, a następnie naciśnij ikonę użytkownika w górnej prawej sekcji aplikacji.", - "Subtitles": "Napisy", - "Suggestions": "Polecane", - "Sunday": "Niedziela", - "Sync": "Synchronizacja", - "SyncJobItemStatusCancelled": "Anulowano", - "SyncJobItemStatusConverting": "Konwertowanie", - "SyncJobItemStatusFailed": "Nieudane", - "SyncJobItemStatusQueued": "Dodano do kolejki", - "SyncJobItemStatusReadyToTransfer": "Gotowe do transferu", - "SyncJobItemStatusRemovedFromDevice": "Usunięto z urządzenia", - "SyncJobItemStatusSynced": "Pobrano", - "SyncJobItemStatusSyncedMarkForRemoval": "Usuwanie z urządzenia", - "SyncJobItemStatusTransferring": "Transferowanie", - "SyncUnwatchedVideosOnly": "Pobieraj tylko nieobejrzane wideo", - "SyncUnwatchedVideosOnlyHelp": "Tylko filmy nieobejrzane zostaną pobrane, a obejrzane będą sukcesywnie usuwane z urządzenia.", - "SyncingDots": "Trwa synchronizacja...", - "TV": "Telewizor", - "Tags": "Znaczniki", - "TagsValue": "Znaczniki: {0}", - "TermsOfUse": "Zasady użytkowania", - "ThankYouForTryingEnjoyOneMinute": "Korzystaj z jednej minuty odtwarzania. Dziękujemy za wypróbowanie Jellyfin.", - "ThemeSongs": "Motywy muzyczne", - "ThemeVideos": "Motywy wideo", - "TheseSettingsAffectSubtitlesOnThisDevice": "Te ustawienia dotyczą napisów na tym urządzeniu", - "Thumb": "Miniatura", - "Thursday": "Czwartek", - "TrackCount": "{0} utwory", - "Trailer": "Zwiastun", - "Trailers": "Zwiastuny", - "Transcoding": "Transkodowanie", - "TryMultiSelect": "Wypróbuj multi-zaznaczanie", - "TryMultiSelectMessage": "Aby edytować kilka rzeczy naraz, po prostu kliknij i przytrzymaj jakąkolwiek miniaturkę i zaznacz obiekty którymi chesz zarządzać. To proste!", - "Tuesday": "Wtorek", - "Uniform": "Jednolity", - "UnlockGuide": "Odblokuj funkcje przewodnika", - "Unplayed": "Nieodtwarzane", - "Unrated": "Nieokreślone", - "UntilIDelete": "Do momentu usunięcia", - "UntilSpaceNeeded": "Tak długo jak starczy przestrzeni dyskowej", - "Up": "W górę", - "Upload": "Przekaż", - "ValueAlbumCount": "{0} albumy", - "ValueDiscNumber": "Dysk {0}", - "ValueEpisodeCount": "{0} odcinki", - "ValueGameCount": "{0} gry", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} filmy", - "ValueMusicVideoCount": "{0} teledyski", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 odcinek", - "ValueOneGame": "1 gra", - "ValueOneItem": "1 pozycja", - "ValueOneMovie": "1 film", - "ValueOneMusicVideo": "1 teledysk", - "ValueOneSeries": "1 serial", - "ValueOneSong": "1 utwór", - "ValueSeconds": "{0} sekund", - "ValueSeriesCount": "{0} seriale", - "ValueSongCount": "{0} utwory", - "ValueSpecialEpisodeName": "Specjalne - {0}", - "Vertical": "Wertykalny", - "VideoBitDepthNotSupported": "Nieobsługiwana głębia bitowa wideo", - "VideoCodecNotSupported": "Nieobsługiwany kodek wideo", - "VideoFramerateNotSupported": "Nieobsługiwana częstotliwość odświeżania wideo", - "VideoLevelNotSupported": "Nieobsługiwany poziom wideo", - "VideoProfileNotSupported": "Nieobsługiwany profil wideo", - "VideoRange": "Zakres wideo", - "VideoResolutionNotSupported": "Nieobsługiwany rozdzielczość wideo", - "ViewAlbum": "Podgląd albumu", - "ViewArtist": "Podgląd wykonawcy", - "VoiceInput": "Wejście głosowe", - "WakeServer": "Wybudzaj serwer", - "WakeServerError": "Wysłano pakiery Wake On LAN do maszyny serwera, ale połączenie z serwer Jellyfin zakończyło się niepowodzeniem. Twoja maszyna potrzebuje więcej czasu do wybudzenia lub serwer Jellyfin może nie działać aktywnie na tej maszynie.", - "WakeServerSuccess": "Powodzenie!", - "Watched": "Obejrzany", - "Wednesday": "Środa", - "WifiRequiredToDownload": "Połączenie WiFi jest wymagane, aby kontynuować pobieranie.", - "Writer": "Scenarzysta", - "Yes": "Tak" -} + "PlaybackSettings": "Ustawienia odtwarzania", + "SubtitleSettings": "Ustawienia napis\u00f3w", + "MessageUnlockAppWithPurchaseOrSupporter": "Odblokuj t\u0119 funkcj\u0119, za niewielk\u0105 jednorazow\u0105 op\u0142at\u0105 lub przy u\u017cyciu aktywnej subskrypcji Emby Premium.", + "MessageUnlockAppWithSupporter": "Odblokuj t\u0119 funkcj\u0119 przy u\u017cyciu subskrypcji Emby Premium.", + "MessageToValidateSupporter": "Je\u015bli posiadasz aktywn\u0105 subskrypcj\u0119 Emby Premium, upewnij si\u0119, \u017ce j\u0105 poprawnie skonfigurowa\u0142e\u015b przy pomocy Kokpitu serwera Emby, do kt\u00f3rego mo\u017cesz uzyska\u0107 dost\u0119p, klikaj\u0105c na pozycj\u0119 Premium menu startowego.", + "ValueSpecialEpisodeName": "Specjalne - {0}", + "Share": "Udost\u0119pnij", + "Add": "Dodaj", + "ServerUpdateNeeded": "Ten serwer Emby wymaga aktualizacji. Odwied\u017a stron\u0119 {0}, aby pobra\u0107 najnowsz\u0105 wersj\u0119.", + "LiveTvRequiresUnlock": "Odbi\u00f3r transmisji telewizyjnych wymaga aktywnej subskrypcji Emby Premiere.", + "AttributeNew": "Nowy", + "Premiere": "Premiera", + "Live": "Na \u017cywo", + "Repeat": "Powt\u00f3rz", + "TrackCount": "{0} utwory", + "ItemCount": "{0} pozycje", + "OriginalAirDateValue": "Data pierwszej emisji: {0}", + "EndsAtValue": "Koniec o {0}", + "HeaderSelectDate": "Wybierz dat\u0119", + "Watched": "Obejrzany", + "AirDate": "Data emisji", + "Played": "Odtworzone", + "ButtonOk": "Ok", + "ButtonCancel": "Anuluj", + "AccessRestrictedTryAgainLater": "Dost\u0119p jest aktualnie ograniczony. Spr\u00f3buj ponownie p\u00f3\u017aniej.", + "ButtonGotIt": "Rozumiem", + "ButtonRestart": "Uruchom ponownie", + "RecordingCancelled": "Anulowano nagranie.", + "SeriesCancelled": "Anulowano nagranie seryjne.", + "RecordingScheduled": "Zaplanowano nagranie.", + "SeriesRecordingScheduled": "Zaplanowano nagranie seryjne.", + "HeaderNewRecording": "Nowe nagranie", + "WakeServer": "Wybudzaj serwer", + "HeaderWakeServer": "Wybudzaj serwer", + "AttemptingWakeServer": "Trwa pr\u00f3ba wybudzenia serwera. Prosz\u0119 czeka\u0107...", + "WakeServerSuccess": "Powodzenie!", + "HeaderCustomizeHomeScreen": "Dostosuj ekran startowy", + "WakeServerError": "Wys\u0142ano pakiery Wake On LAN do maszyny serwera, ale po\u0142\u0105czenie z serwer Emby zako\u0144czy\u0142o si\u0119 niepowodzeniem. Twoja maszyna potrzebuje wi\u0119cej czasu do wybudzenia lub serwer Emby mo\u017ce nie dzia\u0142a\u0107 aktywnie na tej maszynie.", + "Sunday": "Niedziela", + "Monday": "Poniedzia\u0142ek", + "Tuesday": "Wtorek", + "Wednesday": "\u015aroda", + "Thursday": "Czwartek", + "Friday": "Pi\u0105tek", + "Saturday": "Sobota", + "Days": "Dni", + "SortByValue": "Sortowanie wg {0}", + "LabelSortBy": "Sortuj po:", + "LabelSortOrder": "Porz\u0105dek sortowania", + "HeaderPhotoAlbums": "Albumy fotografii", + "Photos": "Fotografie", + "HeaderAppearsOn": "Wyst\u0119puje", + "List": "Lista", + "RecordSeries": "Nagraj seryjnie", + "HeaderCinemaMode": "Tryb kinowy", + "HeaderCloudSync": "Synchronizacja chmurowa", + "Downloads": "Pobrane", + "HeaderMyDownloads": "Moje pobrania", + "HeaderOfflineDownloads": "Media dost\u0119pne lokalnie", + "HeaderOfflineDownloadsDescription": "Umo\u017cliwia pobieranie medi\u00f3w na urz\u0105dzenia klienckie, aby z nich korzysta\u0107 bez konieczno\u015bci po\u0142\u0105czenia z serwerem.", + "CloudSyncFeatureDescription": "Umo\u017cliwia synchronizowanie medi\u00f3w z chmur\u0105, w celu \u0142atwego wykonywania kopii zapasowej, archiwizacji i konwersji.", + "LiveTvFeatureDescription": "Ogl\u0105daj transmisje telewizyjne z dowoln\u0105 aplikacj\u0105 Emby, za pomoc\u0105 zainstalowanego na serwerze Emby tunera telewizyjnego.", + "DvrFeatureDescription": "Zaplanuj pojedyncze nagrania program\u00f3w telewizyjnych, nagrywanie seriali i wi\u0119cej za pomoc\u0105 nagrywarki Emby.", + "CinemaModeFeatureDescription": "Tryb kinowy oferuje prawdziwie kinowe do\u015bwiadczenia, z mo\u017cliwo\u015bci\u0105 odtwarzania zwiastun\u00f3w i niestandardowych prezentacji przed seansem.", + "HeaderFreeApps": "Darmowe aplikacje Emby", + "FreeAppsFeatureDescription": "Korzystaj z darmowego dost\u0119pu do aplikacji Emby na swoich urz\u0105dzeniach.", + "HeaderBecomeProjectSupporter": "Zam\u00f3w subskrypcj\u0119 Premium", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Funkcja automatycznego nagrywania seriali wymaga aktywnej subskrypcji Emby Premium.", + "LabelEmailAddress": "Adres pocztowy:", + "PromoConvertRecordingsToStreamingFormat": "Emby Premier umo\u017cliwia automatyczn\u0105 konwersj\u0119 nagra\u0144 do formatu przyjaznego transmisjom. Nagrania b\u0119d\u0105 konwertowane w flocie do kontenera MP4 lub MKV, w zale\u017cno\u015bci o konfiguracji serwera Emby.", + "FeatureRequiresEmbyPremiere": "Ta funkcja wymaga aktywnej subskrypcji Emby Premium.", + "HeaderConvertYourRecordings": "Konwertuj nagrania", + "Record": "Nagrywaj", + "Save": "Zapisz", + "Edit": "Edycja", + "Download": "Pobierz", + "Downloaded": "Pobrano", + "Downloading": "Pobieranie", + "Advanced": "Zaawansowane", + "Delete": "Usu\u0144", + "HeaderDeleteItem": "Usu\u0144 pozycj\u0119", + "ConfirmDeleteItem": "Usuni\u0119cie tej pozycji usunie j\u0105 zar\u00f3wno z systemu plik\u00f3w jak i z biblioteki medi\u00f3w. Czy chcesz kontynuowa\u0107?", + "Refresh": "Od\u015bwie\u017c", + "RefreshQueued": "Od\u015bwie\u017canie dodane do kolejki zada\u0144.", + "AddToCollection": "Dodaj do kolekcji", + "HeaderAddToCollection": "Dodaj do kolekcji", + "NewCollection": "Nowa kolekcja", + "LabelCollection": "Kolekcja:", + "Help": "Pomoc", + "LabelDisplayMode": "Tryb wy\u015bwietlania:", + "Desktop": "Komputer stacjonarny", + "Mobile": "Telefon \/ tabet", + "TV": "Telewizor", + "DisplayModeHelp": "Okre\u015bla typ urz\u0105dzenia, na kt\u00f3rym uruchomiono Emby.", + "LabelDisplayLanguage": "J\u0119zyk interfejsu:", + "LabelDisplayLanguageHelp": "T\u0142umaczenie Emby to projekt, kt\u00f3ry ci\u0105gle trwa.", + "LearnHowYouCanContribute": "Dowiedz si\u0119 jak mo\u017cesz pom\u00f3c.", + "NewCollectionHelp": "Kolekcje umo\u017cliwiaj\u0105 spersonalizowane grupowanie film\u00f3w i innej zawarto\u015bci biblioteki.", + "SearchForCollectionInternetMetadata": "Wyszukuj grafiki i metadane w Internecie", + "DisplayMissingEpisodesWithinSeasons": "Wy\u015bwietlaj w sezonach brakuj\u0105ce odcinki", + "DisplayMissingEpisodesWithinSeasonsHelp": "Ta opcja, musi zosta\u0107 dodatkowo aktywowana w bibliotece seriali, w konfiguracji serwera Emby.", + "EnableThemeSongs": "Odtwarzaj motywy muzyczne", + "EnableBackdrops": "Wy\u015bwietlaj fototapety", + "EnableThemeSongsHelp": "Umo\u017cliwia odtwarzanie motyw\u00f3w muzycznych podczas przegl\u0105dania biblioteki.", + "EnableBackdropsHelp": "Umo\u017cliwia wy\u015bwietlanie fototapet, w tle niekt\u00f3rych stron, podczas przegl\u0105dania biblioteki.", + "EnableThemeVideos": "Odtwarzaj motywy wideo", + "EnableThemeVideosHelp": "Umo\u017cliwia wy\u015bwietlanie motyw\u00f3w wideo podczas przegl\u0105dania biblioteki,", + "RunAtStartup": "Uruchamiaj po starcie", + "LabelScreensaver": "Wygaszacz ekranu:", + "LabelSoundEffects": "Efekty d\u017awi\u0119kowe", + "LabelSkin": "Sk\u00f3ra:", + "LabelName": "Nazwa:", + "NewCollectionNameExample": "Przyk\u0142ad: Kolekcja Star Wars", + "MessageItemsAdded": "Dodano pozycj\u0119.", + "OptionNew": "Nowa...", + "LabelPlaylist": "Lista odtwarzania:", + "AddToPlaylist": "Dodaj do listy", + "HeaderAddToPlaylist": "Dodaj do listy", + "Subtitles": "Napisy", + "LabelTheme": "Motyw:", + "LabelDashboardTheme": "Motyw kokpitu serwera:", + "SearchForSubtitles": "Wyszukuj napisy", + "LabelLanguage": "J\u0119zyk:", + "Search": "Szukaj", + "NoSubtitleSearchResultsFound": "Brak wynik\u00f3w wyszukiwania.", + "File": "Plik", + "MessageAreYouSureDeleteSubtitles": "Czy jeste\u015b pewien, \u017ce chcesz usun\u0105\u0107 ten plik z napisami?", + "ConfirmDeletion": "Potwierdzenie usuni\u0119cia", + "MySubtitles": "Moje napisy", + "MessageDownloadQueued": "Dodano do kolejki pobierania.", + "EditSubtitles": "Edytuj napisy", + "UnlockGuide": "Odblokuj funkcje przewodnika", + "RefreshMetadata": "Od\u015bwie\u017c metadane", + "ReplaceExistingImages": "Zast\u0119puj istniej\u0105ce obrazy", + "ReplaceAllMetadata": "Zast\u0119puj wszystkie metadane", + "SearchForMissingMetadata": "Wyszukuj brakuj\u0105ce metadane", + "LabelRefreshMode": "Tryb od\u015bwie\u017cania:", + "NoItemsFound": "Brak dost\u0119pnych pozycji.", + "HeaderSaySomethingLike": "Powiedz co\u015b jak...", + "ButtonTryAgain": "Spr\u00f3buj ponownie", + "HeaderYouSaid": "Powiedzia\u0142e\u015b...", + "MessageWeDidntRecognizeCommand": "Przepraszamy, nie rozpoznali\u015bmy tej komendy.", + "MessageIfYouBlockedVoice": "Je\u015bli odm\u00f3wisz aplikacji dost\u0119pu g\u0142osowego, b\u0119dziesz musia\u0142 zmieni\u0107 konfiguracj\u0119 przed ponownym urz\u0105dzeniem.", + "ValueDiscNumber": "Dysk {0}", + "Unrated": "Nieokre\u015blone", + "Favorite": "Ulubione", + "Like": "Lubi\u0119", + "Dislike": "Nie lubi\u0119", + "RefreshDialogHelp": "Metadane s\u0105 od\u015bwie\u017cane w oparciu o ustawienia i dostawc\u00f3w internetowych, aktywowanych w kokpicie serwera Emby.", + "Open": "Otw\u00f3rz", + "Play": "Odtwarzaj", + "AddToPlayQueue": "Dodaj do kolejki odtwarzania", + "Shuffle": "Wylosuj", + "Identify": "Identyfikuj", + "EditImages": "Edytuj obrazy", + "EditMetadata": "Edytuj metadane", + "Convert": "Konwertuj", + "Sync": "Synchronizacja", + "InstantMix": "Szybki remiks", + "ViewAlbum": "Podgl\u0105d albumu", + "ViewArtist": "Podgl\u0105d wykonawcy", + "QueueAllFromHere": "Kolejkuj wszystko z tej lokalizacji", + "PlayAllFromHere": "Odtwarzaj wszystko z tej lokalizacji", + "PlayFromBeginning": "Odtwarzaj od pocz\u0105tku", + "ResumeAt": "Wzn\u00f3w odtwarzanie od {0}", + "RemoveFromPlaylist": "Usu\u0144 z listy", + "RemoveFromCollection": "Usu\u0144 z kolekcji", + "Sort": "Sortuj", + "Trailer": "Zwiastun", + "MarkPlayed": "Oznacz jako obejrzane", + "MarkUnplayed": "Oznacz jako nieobejrzane", + "GroupVersions": "Wersje grup", + "PleaseSelectTwoItems": "Prosz\u0119 wybierz przynajmniej dwie pozycje.", + "TryMultiSelect": "Wypr\u00f3buj multi-zaznaczanie", + "TryMultiSelectMessage": "Aby edytowa\u0107 kilka rzeczy naraz, po prostu kliknij i przytrzymaj jak\u0105kolwiek miniaturk\u0119 i zaznacz obiekty kt\u00f3rymi chesz zarz\u0105dza\u0107. To proste!", + "HeaderConfirmRecordingCancellation": "Potwierd\u017a Anulowanie Nagrania", + "MessageConfirmRecordingCancellation": "Anulowa\u0107 nagranie?", + "Error": "B\u0142\u0105d", + "VoiceInput": "Wej\u015bcie g\u0142osowe", + "LabelContentType": "Typ zawarto\u015bci", + "LabelPath": "Folder:", + "Playlists": "Listy", + "LabelTitle": "Tytu\u0142:", + "LabelOriginalTitle": "Tytu\u0142 oryginalny:", + "LabelSortTitle": "Tytu\u0142 sortowania:", + "LabelDateAdded": "Data dodania:", + "DateAdded": "Data dodania", + "DatePlayed": "Data odtwarzania", + "ConfigureDateAdded": "Spos\u00f3b ustalania daty dodania, mo\u017cna skonfigurowa\u0107, w ustawieniach biblioteki, w kokpicie serwera Emby.", + "LabelStatus": "Stan:", + "LabelArtists": "Wykonawcy:", + "LabelArtistsHelp": "Oddzielaj u\u017cywaj\u0105c ;", + "HeaderAlbumArtists": "Wykonawcy album\u00f3w", + "LabelAlbumArtists": "Wykonawcy album\u00f3w", + "LabelAlbum": "Album", + "Artists": "Wykonawcy", + "ImdbRating": "Ocena IMDb", + "CommunityRating": "Ocena spo\u0142eczno\u015bci", + "LabelCommunityRating": "Ocena spo\u0142eczno\u015bci:", + "LabelCriticRating": "Ocena krytyk\u00f3w:", + "CriticRating": "Ocena krytyk\u00f3w", + "LabelWebsite": "Strona internetowa", + "LabelTagline": "Motto:", + "LabelOverview": "Opis:", + "LabelShortOverview": "Streszczenie:", + "LabelReleaseDate": "Data wydania:", + "LabelYear": "Rok:", + "LabelPlaceOfBirth": "Miejsce urodzenia:", + "Aired": "Premiera", + "LabelAirDays": "Dni transmisji:", + "LabelAirTime": "Czas transmisji:", + "LabelRuntimeMinutes": "Czas (w minutach):", + "LabelParentalRating": "Kategoria wiekowa:", + "LabelCustomRating": "Kategoria wiekowa w\u0142asna:", + "LabelOriginalAspectRatio": "Oryginalny format obrazu:", + "Label3DFormat": "Format 3D:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} pobra\u0144", + "PerfectMatch": "Perfekcyjne dopasowanie", + "EnableExternalVideoPlayers": "Aktywuj obs\u0142ug\u0119 zewn\u0119trznych odtwarzaczy", + "EnableExternalVideoPlayersHelp": "Menu wyboru zewn\u0119trznego odtwarzacza b\u0119dzie wy\u015bwietlane przed rozpocz\u0119ciem odtwarzania wideo.", + "HeaderSpecialEpisodeInfo": "Specjalne informacje o odcinku", + "LabelAirsBeforeSeason": "Emisja przed sezonem:", + "LabelAirsAfterSeason": "Emisja po sezonie:", + "LabelAirsBeforeEpisode": "Emisja przed odcinkiem:", + "HeaderExternalIds": "Identyfikatory zewn\u0119trzne:", + "HeaderDisplaySettings": "Ustawienia wy\u015bwietlania", + "LabelDisplayOrder": "Kolejno\u015b\u0107 wy\u015bwietlania:", + "Display": "Wy\u015bwietlanie", + "Countries": "Kraje", + "Genres": "Gatunki", + "Studios": "Wytw\u00f3rnie", + "Tags": "Znaczniki", + "HeaderMetadataSettings": "Ustawienia metadanych", + "People": "Osoby", + "LabelMetadataDownloadLanguage": "Preferowany j\u0119zyk pobierania:", + "LabelLockItemToPreventChanges": "Zablokuj t\u0119 pozycj\u0119, aby zapobiec przysz\u0142ym zmianom", + "MessageLeaveEmptyToInherit": "Zostaw puste aby odziedziczy\u0107 ustawienia z nadrz\u0119dnej pozycji, lub globalnej warto\u015bci domy\u015blnej.", + "LabelCountry": "Kraj:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Rok urodzenia:", + "LabelBirthDate": "Data urodzenia:", + "LabelDeathDate": "Data \u015bmierci:", + "LabelEndDate": "Data zako\u0144czenia:", + "LabelSeasonNumber": "Numer sezonu:", + "LabelEpisodeNumber": "Numer odcinka:", + "LabelTrackNumber": "Numer utworu:", + "LabelNumber": "Numer:", + "LabelDiscNumber": "Numer dysku:", + "LabelParentNumber": "Numer nadrz\u0119dny:", + "SortName": "Tytu\u0142 sortowania", + "ReleaseDate": "Data wydania", + "Continuing": "Dalej wy\u015bwietlane", + "Ended": "Zako\u0144czony", + "HeaderEnabledFields": "Pola aktywne", + "HeaderEnabledFieldsHelp": "Odznacz pole, aby je zablokowa\u0107 i zapobiec zmianom danych w przysz\u0142o\u015bci.", + "Backdrops": "Fototapety", + "Images": "Obrazy", + "Runtime": "Czas trwania", + "ProductionLocations": "Kraje", + "BirthLocation": "Miejsce urodzin", + "ParentalRating": "Kategoria wiekowa", + "PlayCount": "Liczba odtworze\u0144", + "Name": "Nazwa", + "Overview": "Opis", + "LabelType": "Typ:", + "LabelPersonRole": "Rola:", + "LabelPersonRoleHelp": "Przyk\u0142ad: kierowca ci\u0119\u017car\u00f3wki z lodami", + "Actor": "Aktor", + "Composer": "Kompozytor", + "Director": "Re\u017cyser", + "GuestStar": "Go\u015b\u0107 specjalny", + "Producer": "Producent", + "Writer": "Scenarzysta", + "MessageNoSyncJobsFound": "Brak pobieranych plik\u00f3w. Utw\u00f3rz zadanie pobierania, u\u017cywaj\u0105c przycisku Pobierz, dost\u0119pnego w aplikacji.", + "MessageNoDownloadsFound": "Brak dost\u0119pnych lokalnie medi\u00f3w. Pobierz media do u\u017cycia lokalnie, u\u017cywaj\u0105c przycisku Pobierz, dost\u0119pnego w aplikacji.", + "InstallingPackage": "Instalowanie {0}", + "PackageInstallCompleted": "Instalacja {0} zako\u0144czona.", + "PackageInstallFailed": "Instalacja {0} nieudana.", + "PackageInstallCancelled": "Instalacja {0} anulowana.", + "SeriesYearToPresent": "{0} - Teraz", + "ValueOneItem": "1 pozycja", + "ValueOneSong": "1 utw\u00f3r", + "ValueSongCount": "{0} utwory", + "ValueOneMovie": "1 film", + "ValueMovieCount": "{0} filmy", + "ValueOneSeries": "1 serial", + "ValueSeriesCount": "{0} seriale", + "ValueOneEpisode": "1 odcinek", + "ValueEpisodeCount": "{0} odcinki", + "ValueOneGame": "1 gra", + "ValueGameCount": "{0} gry", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albumy", + "ValueOneMusicVideo": "1 teledysk", + "ValueMusicVideoCount": "{0} teledyski", + "ValueMinutes": "{0} min", + "Albums": "Albumy", + "Songs": "Utwory", + "Books": "Ksi\u0105\u017cki", + "HeaderAudioBooks": "Ksi\u0105\u017cka m\u00f3wiona", + "HeaderIdentifyItemHelp": "Wpisz kryteria wyszukiwania. Zmniejszaj\u0105c ilo\u015b\u0107 kryteri\u00f3w zwi\u0119kszysz ilo\u015b\u0107 wynik\u00f3w.", + "PleaseEnterNameOrId": "Prosz\u0119 wprowad\u017a nazw\u0119 lub zewn\u0119trzne Id.", + "MessageItemSaved": "Obiekt zapisany.", + "SearchResults": "Wyniki wyszukiwania", + "ServerNameIsRestarting": "Emby Server - {0} jest uruchamiany ponownie.", + "ServerNameIsShuttingDown": "Serwer Emby - {0} jest zamykany.", + "HeaderDeleteItems": "Usu\u0144 pliki", + "ConfirmDeleteItems": "Usuni\u0119cie tej pozycji usunie j\u0105 zar\u00f3wno z systemu plik\u00f3w jak i z biblioteki medi\u00f3w. Czy chcesz kontynuowa\u0107?", + "PleaseRestartServerName": "Prosz\u0119 ponownie uruchomi\u0107 serwer Emby - {0}", + "LabelSyncJobName": "Nazwa zadania:", + "SyncingDots": "Trwa synchronizacja...", + "ConvertingDots": "Trwa konwertowanie...", + "LabelQuality": "Jako\u015b\u0107:", + "LabelSyncNoTargetsHelp": "Wygl\u0105da na to, \u017ce nie posiadasz \u017cadnych aplikacji obs\u0142uguj\u0105cych pobrane media.", + "DownloadingDots": "Trwa pobieranie...", + "HeaderSyncRequiresSub": "Pobieranie wymaga aktywnej subskrypcji Emby Premium.", + "LearnMore": "Dowiedz si\u0119 wi\u0119cej", + "LabelProfile": "Profil:", + "LabelBitrateMbps": "Przep\u0142ywno\u015b\u0107 (Mbps):", + "ConvertUnwatchedVideosOnly": "Konwertuj tylko nieobejrzane", + "SyncUnwatchedVideosOnly": "Pobieraj tylko nieobejrzane wideo", + "ConvertUnwatchedVideosOnlyHelp": "Tylko nieobejrzane wideo b\u0119d\u0105 konwertowane.", + "SyncUnwatchedVideosOnlyHelp": "Tylko filmy nieobejrzane zostan\u0105 pobrane, a obejrzane b\u0119d\u0105 sukcesywnie usuwane z urz\u0105dzenia.", + "AutomaticallySyncNewContent": "Pobieraj now\u0105 zawarto\u015b\u0107 automatycznie", + "AutomaticallySyncNewContentHelp": "Nowo dodana zawarto\u015b\u0107 zostanie automatycznie pobrana na urz\u0105dzenie.", + "AutomaticallyConvertNewContent": "Konwertuj automatycznie nowe media", + "AutomaticallyConvertNewContentHelp": "Nowe media dodane do tego folderu b\u0119d\u0105 konwertowane automatycznie.", + "LabelItemLimit": "Limit pozycji:", + "ConvertItemLimitHelp": "Opcjonalne. Okre\u015bla maksymaln\u0105 liczb\u0119 konwertowanych pozycji.", + "DownloadItemLimitHelp": "Opcjonalne. Okre\u015bla maksymaln\u0105 liczb\u0119 pobieranych pozycji.", + "PleaseSelectDeviceToSyncTo": "Wybierz urz\u0105dzenie, na kt\u00f3re chcesz pobra\u0107.", + "Screenshots": "Zrzuty ekranu", + "MoveRight": "Przesu\u0144 w prawo", + "MoveLeft": "Przesu\u0144 w lewo", + "ConfirmDeleteImage": "Usun\u0105\u0107 obraz?", + "HeaderEditImages": "Edytuj obrazy", + "Settings": "Ustawienia", + "ShowIndicatorsFor": "Pokazuj wska\u017aniki dla:", + "NewEpisodes": "Nowe odcinki", + "Episodes": "Odcinki", + "HDPrograms": "Programy w jako\u015bci HD", + "Programs": "Programy", + "LiveBroadcasts": "Transmisje na \u017cywo", + "Premieres": "Premiery", + "RepeatEpisodes": "Powtarzaj odcinki", + "DvrSubscriptionRequired": "Funkcja nagrywarki wymaga aktywnej subskrypcji Emby Premium.", + "HeaderCancelRecording": "Anuluj nagranie", + "CancelRecording": "Anuluj nagranie", + "HeaderKeepRecording": "Zachowaj nagranie", + "HeaderCancelSeries": "Anuluj nagrywanie serialu", + "HeaderKeepSeries": "Zachowaj nagranie serialu", + "HeaderLearnMore": "Dowiedz si\u0119 wi\u0119cej", + "DeleteMedia": "Usu\u0144 pozycj\u0119", + "SeriesSettings": "Ustawienia nagrywania serialu", + "HeaderRecordingOptions": "Opcje nagrywania", + "CancelSeries": "Anuluj nagrywanie serialu", + "DoNotRecord": "Nie nagrywaj", + "HeaderSeriesOptions": "Opcje nagrywania serialu", + "LabelChannels": "Kana\u0142y:", + "ChannelNameOnly": "Tylko kana\u0142 {0}", + "Anytime": "O dowolnej porze", + "AnyLanguage": "W dowolnym j\u0119zyku", + "AroundTime": "Oko\u0142o {0}", + "All": "Wszystkie", + "AllChannels": "Wszystkie kana\u0142y", + "LabelRecord": "Nagraj:", + "NewEpisodesOnly": "Tylko nowe odcinki", + "AllEpisodes": "Wszystkie odcinki", + "LabelStartWhenPossible": "Zaczynaj kiedy mo\u017cliwe:", + "LabelStopWhenPossible": "Zatrzymuj kiedy mo\u017cliwe:", + "MinutesBefore": "minut przed", + "MinutesAfter": "minut po", + "SkipEpisodesAlreadyInMyLibrary": "Pomijaj nagrywanie odcink\u00f3w, kt\u00f3re ju\u017c s\u0105 w bibliotece", + "SkipEpisodesAlreadyInMyLibraryHelp": "Odcinki b\u0119d\u0105 por\u00f3wnywane przy pomocy numeru sezonu i odcinka, je\u015bli s\u0105 dost\u0119pne.", + "LabelKeepUpTo": "Zachowuj do:", + "AsManyAsPossible": "Tak wiele jak to mo\u017cliwe", + "DefaultErrorMessage": "Wyst\u0105pi\u0142 bl\u0105d podczas przetwarzania twojego rz\u0105dania. Prosz\u0119 spr\u00f3bowa\u0107 ponownie po\u017aniej.", + "LabelKeep:": "Zachowuj:", + "UntilIDelete": "Do momentu usuni\u0119cia", + "UntilSpaceNeeded": "Tak d\u0142ugo jak starczy przestrzeni dyskowej", + "Categories": "Kategorie", + "Sports": "Wydarzenia sportowe", + "News": "Wiadomo\u015bci", + "Movies": "Filmy", + "Kids": "Dla dzieci", + "EnableColorCodedBackgrounds": "Aktywuj kolorowe t\u0142a bazuj\u0105ce na zawarto\u015bci", + "SortChannelsBy": "Sortuj kana\u0142y wg:", + "RecentlyWatched": "Ostatnio obejrzane", + "ChannelNumber": "Numer kana\u0142u", + "HeaderBenefitsEmbyPremiere": "Korzy\u015bci z subskrypcji Premium", + "ThankYouForTryingEnjoyOneMinute": "Korzystaj z jednej minuty odtwarzania. Dzi\u0119kujemy za wypr\u00f3bowanie Emby.", + "HeaderTryPlayback": "Wypr\u00f3buj odtwarzanie", + "HowDidYouPay": "W jaki spos\u00f3b zap\u0142aci\u0142e\u015b?", + "IHaveEmbyPremiere": "Posiadam subskrypcj\u0119 Emby Premium", + "IPurchasedThisApp": "Kupi\u0142em t\u0119 aplikacj\u0119", + "ButtonRestorePreviousPurchase": "Przywr\u00f3\u0107 zakup", + "ButtonUnlockWithPurchase": "Odblokuj zamawiaj\u0105c subskrypcj\u0119", + "ButtonUnlockPrice": "Odblokuj {0}", + "EmbyPremiereMonthlyWithPrice": "Miesi\u0119czna subskrypcja Emby Premium {0}", + "HeaderAlreadyPaid": "Ju\u017c op\u0142acone?", + "ButtonPlayOneMinute": "Odtwarzaj jedn\u0105 minut\u0119", + "PlaceFavoriteChannelsAtBeginning": "Umieszczaj ulubione kana\u0142y na pocz\u0105tku", + "HeaderUnlockFeature": "Odblokuj funkcj\u0119", + "MessageDidYouKnowCinemaMode": "Czy wiedzia\u0142e\u015b, \u017ce dzi\u0119ki subskrypcji Emby Premium, mo\u017cesz rozszerzy\u0107 mo\u017cliwo\u015bci serwera o dodatkowe funkcje, takiej jak Tryb Kinowy?", + "MessageDidYouKnowCinemaMode2": "Tryb kinowy oferuje prawdziwie kinowe do\u015bwiadczenia, z mo\u017cliwo\u015bci\u0105 odtwarzania zwiastun\u00f3w i niestandardowych prezentacji przed seansem.", + "HeaderPlayMyMedia": "Odtwarzaj pozycj\u0119", + "HeaderDiscoverEmbyPremiere": "Odkryj funkcje Emby Premium", + "Items": "Pozycje", + "OneChannel": "Jeden kana\u0142", + "ConfirmRemoveDownload": "Usun\u0105\u0107 pobran\u0105 pozycj\u0119?", + "RemoveDownload": "Usu\u0144 pobran\u0105 pozycj\u0119", + "KeepDownload": "Zachowaj pobran\u0105 pozycj\u0119", + "AddedOnValue": "Dodano {0}", + "RemovingFromDevice": "Usu\u0144 z urz\u0105dzenia", + "KeepOnDevice": "Zachowaj na urz\u0105dzeniu", + "CancelDownload": "Anuluj pobieranie", + "SyncJobItemStatusReadyToTransfer": "Gotowe do transferu", + "SyncJobItemStatusSyncedMarkForRemoval": "Usuwanie z urz\u0105dzenia", + "SyncJobItemStatusQueued": "Dodano do kolejki", + "SyncJobItemStatusConverting": "Konwertowanie", + "SyncJobItemStatusTransferring": "Transferowanie", + "SyncJobItemStatusSynced": "Pobrano", + "SyncJobItemStatusFailed": "Nieudane", + "SyncJobItemStatusRemovedFromDevice": "Usuni\u0119to z urz\u0105dzenia", + "SyncJobItemStatusCancelled": "Anulowano", + "Retry": "Pon\u00f3w", + "HeaderMyDevice": "Moje urz\u0105dzenie", + "Continue": "Kontynuuj", + "ContinueInSecondsValue": "Kontynuuj za {0} sekund.", + "HeaderRemoteControl": "Zdalne sterowanie", + "Disconnect": "Roz\u0142\u0105cz", + "EnableDisplayMirroring": "Aktywuj wy\u015bwietlanie lustrzane", + "HeaderPlayOn": "Odtwarzaj na", + "Quality": "Jako\u015b\u0107", + "Auto": "Automatycznie", + "AndroidUnlockRestoreHelp": "W celu odzyskania poprzedniego zakupu, upewnij si\u0119, \u017ce zalogowa\u0142e\u015b si\u0119 na urz\u0105dzeniu przy pomocy tego samego konta Google (lub Amazon), kt\u00f3rym pierwotnie dokona\u0142e\u015b zakupu. Upewnij si\u0119, \u017ce sklep aplikacji dzia\u0142a poprawnie i nie jest ograniczony kontrol\u0105 rodzicielsk\u0105, a Twoje po\u0142\u0105czenie z Internetem jest aktywne. Musisz to zrobi\u0107 tylko raz, aby przywr\u00f3ci\u0107 poprzedni zakup.", + "AspectRatio": "Proporcje obrazu", + "Original": "Orignalne", + "Fill": "Rozci\u0105gnij", + "BestFit": "Najlepsze dopasowane", + "MessageNoServersAvailableToConnect": "Brak serwer\u00f3w dost\u0119pnych do po\u0142\u0105czenia. Je\u015bli zosta\u0142e\u015b zaproszony do korzystania z serwera, upewnij si\u0119, \u017ce je zaakceptowa\u0142e\u015b poni\u017cej lub za naciskaj\u0105c na \u0142\u0105cze w wiadomo\u015bci pocztowej.", + "MessagePlayAccessRestricted": "Odtwarzanie tej zawarto\u015bci jest aktualnie ograniczone. Skontaktuj si\u0119 z administratorem serwera, aby uzyska\u0107 dodatkowe informacje.", + "Accept": "Akceptuj", + "Reject": "Odrzu\u0107", + "Connect": "Po\u0142acz", + "HeaderMyMedia": "Moje media", + "HeaderMyMediaSmall": "Moje media (ma\u0142e)", + "LatestFromLibrary": "{0} ostatnio dodane", + "ContinueWatching": "Kontynuuj odtwarzanie", + "HeaderLatestChannelMedia": "Kana\u0142y ostatnio dodane", + "HeaderContinueWatching": "Kontynuuj odtwarzanie", + "HeaderContinueListening": "Kontynuuj s\u0142uchanie", + "HeaderActiveRecordings": "Nagrania aktywne", + "HeaderLatestRecordings": "Nagrania ostatnio dodane", + "LabelSyncTo": "Synchronizuj z:", + "LabelConvertTo": "Konwertuj do:", + "Next": "Nast\u0119pny", + "LabelSource": "\u0179r\u00f3d\u0142o:", + "LabelVersion": "Wersja:", + "AllLanguages": "Wszystkie j\u0119zyki", + "Previous": "Poprzedni", + "HeaderNextUp": "Do obejrzenia", + "HeaderLatestFrom": "{0} ostatnio dodane", + "LabelHomeScreenSectionValue": "Sekcja ekranu startowego {0}:", + "SettingsSaved": "Zapisano ustawienia", + "None": "Brak", + "More": "Wi\u0119cej", + "Up": "W g\u00f3r\u0119", + "Down": "W d\u00f3\u0142", + "Home": "Start", + "Favorites": "Ulubione", + "HeaderHomeScreen": "Ekran startowy", + "HeaderLatestChannelItems": "Kana\u0142y ostatnio odtwarzane", + "HeaderLibraryOrder": "Kolejno\u015b\u0107 biblioteki", + "HideWatchedContentFromLatestMedia": "Ukrywaj obejrzan\u0105 zawarto\u015b\u0107 na listach ostatnio dodanych", + "HeaderOnNow": "Teraz", + "HeaderPlaybackError": "B\u0142\u0105d Odtwarzania", + "PlaybackErrorNotAllowed": "Brak uprawnie\u0144 do odtwarzania tej zawarto\u015bci. Skontaktuj si\u0119 z administratorem serwera, aby uzyska\u0107 dodatkowe informacje.", + "PlaybackErrorNoCompatibleStream": "Brak kompatybilnych transmisji. Spr\u00f3buj ponownie p\u00f3\u017aniej lub skontaktuj si\u0119 z administratorem serwera, aby uzyska\u0107 dodatkowe informacje.", + "PlaybackErrorPlaceHolder": "Prosz\u0119 w\u0142o\u017cy\u0107 dysk, aby odtwarza\u0107 to wideo.", + "Guide": "Przewodnik", + "Suggestions": "Polecane", + "HeaderFavoriteCollections": "Kolekcje ulubione", + "HeaderFavoritePlaylists": "Listy ulubione", + "Collections": "Kolekcje", + "LabelSelectFolderGroups": "Grupuj zawarto\u015b\u0107 z nast\u0119puj\u0105cych folder\u00f3w w widokach taki, jak Filmy, Muzyka i Seriale:", + "LabelSelectFolderGroupsHelp": "Foldery, kt\u00f3re nie zosta\u0142y zaznaczone, b\u0119d\u0105 wy\u015bwietlane w swoich w\u0142asnych, osobnych widokach.", + "Folders": "Foldery", + "DisplayInOtherHomeScreenSections": "Wy\u015bwietlaj na ekranie startowym sekcje Ostatnio dodane i Kontynuuj odtwarzanie", + "DisplayInMyMedia": "Wy\u015bwietlaj na ekranie startowym", + "Shows": "Seriale", + "HeaderLibraryFolders": "Foldery biblioteki", + "HeaderTermsOfPurchase": "Zasady zakupu", + "PrivacyPolicy": "Polityka prywatno\u015bci", + "TermsOfUse": "Zasady u\u017cytkowania", + "RepeatMode": "Tryb powtarzania", + "RepeatOne": "Powtarzaj jedno", + "RepeatAll": "Powtarzaj wszystko", + "LabelDefaultScreen": "Ekran domy\u015blny:", + "ConfirmEndPlayerSession": "Czy chcesz zamkn\u0105\u0107 Emby na {0}?", + "Yes": "Tak", + "No": "Nie", + "LiveTV": "Telewizja", + "Schedule": "Zaplanuj", + "Recordings": "Nagrania", + "MarkWatched": "Oznacz jako obejrzane", + "ScanForNewAndUpdatedFiles": "Skanuj w poszukiwaniu nowych lub zaktualizowanych plik\u00f3w", + "DirectStreamHelp1": "Media s\u0105 kompatybilne z urz\u0105dzeniem w kwestii rozdzielczo\u015bci i typu (H.264, AC3, etc), ale kontener pliku jest niekompatybilny (.mkv, .avi, .wmv, etc). Wideo zostanie przepakowane w locie przed rozpocz\u0119ciem transmisji do urz\u0105dzenia.", + "DirectStreamHelp2": "Transmisja bezpo\u015brednia pliku u\u017cywa niewiele mocy przetwarzania, bez utraty jako\u015bci wideo.", + "MediaIsBeingConverted": "Media b\u0119d\u0105 konwertowane do formatu kompatybilnego z urz\u0105dzeniem, na kt\u00f3ry b\u0119d\u0105 odtwarzane.", + "StatsForNerds": "Statystyki dla maniak\u00f3w", + "LabelReasonForTranscoding": "Pow\u00f3d transkodowania", + "DirectPlaying": "Odtwarzanie bezpo\u015brednie", + "DirectStreaming": "Transmisja bezpo\u015brednia", + "Transcoding": "Transkodowanie", + "ContainerBitrateExceedsLimit": "Przep\u0142ywno\u015b\u0107 medi\u00f3w przekracza limit.", + "VideoCodecNotSupported": "Nieobs\u0142ugiwany kodek wideo", + "AudioCodecNotSupported": "Nieobs\u0142ugiwany kodek d\u017awi\u0119ku", + "SubtitleCodecNotSupported": "Nieobs\u0142ugiwany format napis\u00f3w", + "DirectPlayError": "Nieudane odtwarzanie bezpo\u015brednie", + "ContainerNotSupported": "Nieobs\u0142ugiwany format kontenera", + "VideoLevelNotSupported": "Nieobs\u0142ugiwany poziom wideo", + "AudioBitrateNotSupported": "Nieobs\u0142ugiwana przep\u0142ywno\u015b\u0107 d\u017awi\u0119ku", + "AudioChannelsNotSupported": "Nieobs\u0142ugiwany liczba kana\u0142\u00f3w d\u017awi\u0119ku", + "VideoResolutionNotSupported": "Nieobs\u0142ugiwany rozdzielczo\u015b\u0107 wideo", + "AudioProfileNotSupported": "Nieobs\u0142ugiwany profil d\u017awi\u0119ku", + "AudioSampleRateNotSupported": "Nieobs\u0142ugiwana cz\u0119stotliwo\u015b\u0107 pr\u00f3bkowania d\u017awi\u0119ku", + "AnamorphicVideoNotSupported": "Nieobs\u0142ugiwane wideo anamorficzne", + "InterlacedVideoNotSupported": "Nieobs\u0142ugiwane wideo z przeplotem", + "SecondaryAudioNotSupported": "Nieobs\u0142ugiwane prze\u0142\u0105czanie \u015bcie\u017cek d\u017awi\u0119kowych", + "ErrorRemovingEmbyConnectAccount": "Podczas usuwania konta Emby Connect wyst\u0105pi\u0142 b\u0142\u0105d. Upewnij si\u0119, \u017ce po\u0142\u0105czenie internetowe jest aktywne i spr\u00f3buj ponownie.", + "HeaderEmbyAccountRemoved": "Usuni\u0119to konto Emby", + "MessageEmbyAccontRemoved": "Konto Emby zosta\u0142o usuni\u0119te dla tego u\u017cytkownika.", + "HeaderInvitationSent": "Wys\u0142ano zaproszenie", + "MessageInvitationSentToUser": "Wiadomo\u015b\u0107 pocztowa, z pro\u015bb\u0105 o akceptacj\u0119 zaproszenia wsp\u00f3\u0142u\u017cytkowania, zosta\u0142a wys\u0142ana do {0}.", + "MessageInvitationSentToNewUser": "Wiadomo\u015b\u0107 pocztowa, z pro\u015bb\u0105 o rejestracj\u0119 konta Emby, zosta\u0142a wys\u0142ana do {0}.", + "GuestUserNotFound": "U\u017cytkownik nie istnieje. Upewnij si\u0119, \u017ce nazwa jest poprawna lub spr\u00f3buj wprowadzaj\u0105c adres pocztowy.", + "ErrorReachingEmbyConnect": "Podczas pr\u00f3by po\u0142\u0105czenia z serwerem Emby Connect wyst\u0105pi\u0142 b\u0142\u0105d. Upewnij si\u0119, \u017ce po\u0142\u0105czenie internetowe jest aktywne i spr\u00f3buj ponownie.", + "ErrorAddingEmbyConnectAccount1": "Podczas dodawania konta Emby Connect wyst\u0105pi\u0142 b\u0142\u0105d. Czy utworzy\u0142e\u015b wcze\u015bniej konto Emby?. Zarejestruj si\u0119 na {0}.", + "ErrorAddingEmbyConnectAccount2": "Je\u015bli ci\u0105gle masz problem, wy\u015blij wiadomo\u015bci na adres {0}, z adresu pocztowego skojarzonego z kontem Emby.", + "ErrorAddingGuestAccount1": "Podczas dodawania konta Emby Connect wyst\u0105pi\u0142 b\u0142\u0105d. Czy u\u017cytkownik go\u015bcinny utworzy\u0142 konto Emby? U\u017cytkownicy go\u015bcinni mog\u0105 si\u0119 zarejestrowa\u0107 na stronie {0}.", + "ErrorAddingGuestAccount2": "Je\u015bli ci\u0105gle masz problem, wy\u015blij wiadomo\u015bci na adres {0}, podaj\u0105c sw\u00f3j adres pocztowy oraz swoich u\u017cytykownik\u00f3w.", + "MessageEmbyAccountAdded": "Konto Emby zosta\u0142o dodane do u\u017cytkownika.", + "MessagePendingEmbyAccountAdded": "Konto Emby zosta\u0142o po\u0142\u0105czone z tym u\u017cytkownikiem. Wiadomo\u015b\u0107 pocztowa zosta\u0142a wys\u0142ana do w\u0142a\u015bciciela tego konta. Wymagane b\u0119dzie potwierdzenie zaproszenia, poprzez naci\u015bni\u0119cie na \u0142\u0105cze umieszczone w wiadomo\u015bci.", + "HeaderEmbyAccountAdded": "Dodano konto Emby", + "LabelSubtitlePlaybackMode": "Tryb napis\u00f3w:", + "ErrorDeletingItem": "Podczas usuwania pozycji z serwera Emby wyst\u0105pi\u0142 b\u0142\u0105d. Upewnij si\u0119, \u017ce serwer ma uprawnienia do zapisu w folderze medi\u00f3w i spr\u00f3buj ponownie.", + "NoSubtitles": "Brak napis\u00f3w", + "Default": "Domy\u015blny", + "Absolute": "Bezwzgl\u0119dnie", + "Smart": "Inteligentny", + "Small": "Ma\u0142y", + "Smaller": "Mniejsze", + "Medium": "\u015aredni", + "Large": "Du\u017cy", + "ExtraLarge": "Wielki", + "OnlyForcedSubtitles": "Tylko wymuszone napisy", + "AlwaysPlaySubtitles": "Zawsze wy\u015bwietlaj napisy", + "DefaultSubtitlesHelp": "Napisy b\u0119d\u0105 wczytywane w oparciu o znaczniki metadanych \u015bcie\u017cek d\u017awi\u0119kowych. Preferencje j\u0119zykowe brane s\u0105 pod uwag\u0119, gdy dost\u0119pnych jest wiele mo\u017cliwo\u015bci.", + "SmartSubtitlesHelp": "W przypadku, gdy \u015bcie\u017cka d\u017awi\u0119kowa jest w j\u0119zyku obcym, zostan\u0105 wczytane napisy w preferowanym j\u0119zyku.", + "HeaderSubtitleSettings": "Ustawienia napis\u00f3w", + "HeaderSubtitleAppearance": "Wygl\u0105d napis\u00f3w", + "OnlyForcedSubtitlesHelp": "Tylko napisy oznaczone jako wymuszone b\u0119d\u0105 wczytywane.", + "AlwaysPlaySubtitlesHelp": "Napisy pasuj\u0105ce do preferowanego j\u0119zyka b\u0119d\u0105 wczytywane, niezale\u017cnie od j\u0119zyka \u015bcie\u017cki d\u017awi\u0119kowej.", + "NoSubtitlesHelp": "Domy\u015blnie napisy nie b\u0119d\u0105 wczytywane. Mo\u017cna je ci\u0105gle w\u0142\u0105czy\u0107 r\u0119cznie podczas odtwarzania.", + "LabelPreferredSubtitleLanguage": "Preferowany j\u0119zyk napis\u00f3w:", + "LabelTextSize": "Rozmiar tekstu:", + "TheseSettingsAffectSubtitlesOnThisDevice": "Te ustawienia dotycz\u0105 napis\u00f3w na tym urz\u0105dzeniu", + "LabelDropShadow": "Cie\u0144:", + "LabelTextBackgroundColor": "Kolor t\u0142a tekstu:", + "LabelWindowBackgroundColor": "Kolor t\u0142a tekstu:", + "LabelFont": "Czcionka:", + "LabelTextColor": "Kolor tekstu:", + "Raised": "Wypuk\u0142y", + "Depressed": "Wkl\u0119s\u0142y", + "Uniform": "Jednolity", + "DropShadow": "Rozproszony", + "SmallCaps": "Kapitaliki", + "SubtitleAppearanceSettingsDisclaimer": "Te ustawienia nie maj\u0105 zastosowania do napis\u00f3w graficznych (PGS, DVD, etc) lub napis\u00f3w, kt\u00f3re posiadaj\u0105 swoje w\u0142asne wbudowane style (ASS\/SSA).", + "LabelBurnSubtitles": "Wypalaj napisy:", + "OnlyImageFormats": "Tylko formaty graficzne (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normalny", + "BurnSubtitlesHelp": "Okre\u015bla czy serwer powinien wypala\u0107 napisy podczas konwersji wideo, w zale\u017cno\u015bci od formatu napis\u00f3w. Unikanie wypalania napis\u00f3w poprawia wydajno\u015b\u0107 serwera. Wybierz Automatycznie, w celu wypalania zar\u00f3wno napis\u00f3w w formatach graficznych (np. VOBSUB, PGS, SUB\/IDX, itp.), jak i pewnych napis\u00f3w ASS\/SSA.", + "AllComplexFormats": "Wszystkie z\u0142o\u017cone formaty (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Powy\u017csze ustawienia dotycz\u0105 tak\u017ce odtwarzania Chromecast rozpocz\u0119tego przez to urz\u0105dzenie.", + "HeaderWaitingForWifi": "Oczekiwanie na sie\u0107 WiFi", + "WifiRequiredToDownload": "Po\u0142\u0105czenie WiFi jest wymagane, aby kontynuowa\u0107 pobieranie.", + "HeaderDownloadSettings": "Ustawienia pobierania", + "Hide": "Ukryj", + "HeaderStartNow": "Rozpocznij teraz", + "HeaderNextVideoPlayingInValue": "Nast\u0119pne wideo za {0}", + "HeaderNextEpisodePlayingInValue": "Nast\u0119pne odcinek za {0}", + "HeaderSecondsValue": "{0} sekund", + "AudioBitDepthNotSupported": "Nieobs\u0142ugiwana g\u0142\u0119bia bitowa d\u017awi\u0119ku", + "VideoProfileNotSupported": "Nieobs\u0142ugiwany profil wideo", + "VideoFramerateNotSupported": "Nieobs\u0142ugiwana cz\u0119stotliwo\u015b\u0107 od\u015bwie\u017cania wideo", + "VideoBitDepthNotSupported": "Nieobs\u0142ugiwana g\u0142\u0119bia bitowa wideo", + "RefFramesNotSupported": "Nieobs\u0142ugiwana liczba klatek referencyjnych wideo", + "ErrorConnectServerUnreachable": "Podczas wykonywania \u017c\u0105danej operacji wyst\u0105pi\u0142 b\u0142\u0105d. Po\u0142\u0105czenie z Twojego serwera z serwerem Emby Connect z {0} by\u0142o niemo\u017cliwe. Upewnij si\u0119, \u017ce po\u0142\u0105czenie internetowe na Twoim serwerze jest aktywne i komunikacja jest dozwolona przez zapor\u0119 sieciow\u0105 i zainstalowane oprogramowanie antywirusowe.", + "StopRecording": "Zatrzymaj nagrywanie", + "HeaderStopRecording": "Zatrzymaj nagrywanie", + "ManageRecording": "Zarz\u0105dzaj nagrywaniem", + "LabelDropImageHere": "Upu\u015b\u0107 obraz tutaj lub naci\u015bnij przycisk, aby przegl\u0105da\u0107.", + "MessageFileReadError": "Podczas wczytywania plik\u00f3w wyst\u0105pi\u0142 b\u0142\u0105d. Spr\u00f3buj ponownie p\u00f3\u017aniej.", + "Browse": "Przegl\u0105daj", + "HeaderUploadImage": "Przeka\u017c obraz", + "HeaderAddUpdateImage": "Dodaj \/ Aktualizuj obraz", + "LabelImageType": "Typ obrazu:", + "Upload": "Przeka\u017c", + "Primary": "Podstawowy", + "Art": "Przezrocze", + "Backdrop": "Fototapeta", + "Banner": "Baner", + "Box": "Pude\u0142ko", + "BoxRear": "Pude\u0142ko (ty\u0142)", + "Disc": "Dysk", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Zrzut ekranu", + "Thumb": "Miniatura", + "ValueSeconds": "{0} sekund", + "HeaderAudioSettings": "Ustawienia d\u017awi\u0119ku", + "LabelAudioLanguagePreference": "Preferowany j\u0119zyk \u015bcie\u017cki d\u017awi\u0119kowej", + "LabelPlayDefaultAudioTrack": "Odtwarzaj domy\u015bln\u0105 \u015bcie\u017ck\u0119 d\u017awi\u0119kow\u0105 niezale\u017cnie od j\u0119zyka", + "HeaderVideoQuality": "Jako\u015b\u0107 wideo", + "CinemaModeConfigurationHelp": "Tryb kinowy, wnosi kinowe do\u015bwiadczenia wprost do Twojego salonu, z mo\u017cliwo\u015bci\u0105 odtwarzania zwiastun\u00f3w i niestandardowych prezentacji przez seansem.", + "EnableNextVideoInfoOverlay": "Pokazuj nast\u0119pne wideo podczas odtwarzania", + "EnableNextVideoInfoOverlayHelp": "Umo\u017cliwia wy\u015bwietlanie pod koniec odtwarzania wideo, informacji o nast\u0119pnym wideo na li\u015bcie odtwarzania.", + "PlayNextEpisodeAutomatically": "Odtwarzaj nast\u0119pny odcinek automatycznie", + "LabelMaxChromecastBitrate": "Jako\u015b\u0107 transmisji Chromecast:", + "LabelSkipBackLength": "D\u0142ugo\u015b\u0107 skoku wstecz:", + "LabelSkipForwardLength": "D\u0142ugo\u015b\u0107 skoku wprz\u00f3d:", + "EnableCinemaMode": "W\u0142\u0105cz tryb kinowy", + "LabelInternetQuality": "Jako\u015b\u0107 dla sieci internetowej:", + "HeaderMusicQuality": "Jako\u015b\u0107 muzyki", + "LabelHomeNetworkQuality": "Jako\u015b\u0107 dla sieci lokalnej:", + "HeaderLatestMedia": "Media ostatnio dodane", + "HeaderRestartingEmbyServer": "Trwa ponownie uruchomienie serwera Emby", + "RestartPleaseWaitMessage": "Czekaj na zamkni\u0119cie i ponowne uruchomienie serwera Emby. To mo\u017ce trwa\u0107 ok. jednej, dw\u00f3ch minut.", + "PlayNext": "Odtwarzaj nast\u0119pne", + "AllowSeasonalThemes": "Zezwalaj na automatyczne motywy sezonowe", + "AllowSeasonalThemesHelp": "Je\u015bli aktywne, motywy sezonowe b\u0119d\u0105 sporadycznie nadpisywa\u0107 Twoje ustawienia motywu.", + "AutoBasedOnLanguageSetting": "Automatyczna (w oparciu o ustawienia j\u0119zykowe)", + "LabelDateTimeLocale": "Strefa czasowa:", + "DirectorValue": "Re\u017cyser: {0}", + "DirectorsValue": "Re\u017cyserzy: {0}", + "GenreValue": "Gatunek: {0}", + "GenresValue": "Gatunki: {0}", + "LinksValue": "\u0141\u0105cza: {0}", + "TagsValue": "Znaczniki: {0}", + "LabelAudio": "D\u017awi\u0119k:", + "LabelVideo": "Wideo:", + "LabelSubtitles": "Napisy:", + "Off": "Wy\u0142\u0105czone", + "ShowTitle": "Pokazuj tytu\u0142", + "ShowYear": "Pokazuj rok", + "Filters": "Filtry", + "Unplayed": "Nieodtwarzane", + "LabelTVHomeScreen": "Ekran startowy trybu telewizyjnego:", + "Horizontal": "Horyzontalny", + "Vertical": "Wertykalny", + "GroupBySeries": "Grupuj po serialach", + "HeaderVideoType": "Typ wideo", + "HeaderSeriesStatus": "Stan serialu", + "Features": "Funkcje", + "Trailers": "Zwiastuny", + "Extras": "Materia\u0142y dodatkowe", + "ThemeSongs": "Motywy muzyczne", + "ThemeVideos": "Motywy wideo", + "HeaderFavoriteMovies": "Filmy ulubione", + "HeaderFavoriteShows": "Seriale ulubione", + "HeaderFavoriteEpisodes": "Odcinki ulubione", + "HeaderFavoriteVideos": "Wideo ulubione", + "HeaderFavoriteGames": "Gry ulubione", + "HeaderFavoriteArtists": "Wykonawcy ulubieni", + "HeaderFavoriteAlbums": "Albumy ulubione", + "HeaderFavoriteSongs": "Utwory ulubione", + "Ascending": "Rosn\u0105co", + "Descending": "Malej\u0105co", + "ColorPrimaries": "Wzorce kolor\u00f3w", + "ColorSpace": "Przestrze\u0144 kolor\u00f3w", + "ColorTransfer": "Transfer kolor\u00f3w", + "VideoRange": "Zakres wideo", + "SeriesDisplayOrderHelp": "Sortuje odcinki po dacie emisji, kolejno\u015bci na DVD lub bezwzgl\u0119dnej numeracji.", + "PlaybackSettingsIntro": "W celu skonfigurowania domy\u015blnych ustawie\u0144 odtwarzania, zatrzymaj odtwarzanie, a nast\u0119pnie naci\u015bnij ikon\u0119 u\u017cytkownika w g\u00f3rnej prawej sekcji aplikacji.", + "SubtitleSettingsIntro": "W celu skonfigurowania domy\u015blnych ustawie\u0144 napis\u00f3w i j\u0119zyka, zatrzymaj odtwarzanie, a nast\u0119pnie naci\u015bnij ikon\u0119 u\u017cytkownika w g\u00f3rnej prawej sekcji aplikacji." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/pt-br.json b/src/bower_components/emby-webcomponents/strings/pt-br.json index 25a47b1648..0afad2c90f 100644 --- a/src/bower_components/emby-webcomponents/strings/pt-br.json +++ b/src/bower_components/emby-webcomponents/strings/pt-br.json @@ -1,685 +1,689 @@ { - "Absolute": "Absoluto", - "Accept": "Aceitar", - "AccessRestrictedTryAgainLater": "O acesso está atualmente restrito. Por favor, tente novamente mais tarde.", - "Actor": "Ator", - "Add": "Adicionar", - "AddToCollection": "Adicionar à coletânea", - "AddToPlayQueue": "Adicionar à fila de reprodução", - "AddToPlaylist": "Adicionar à lista de reprodução", - "AddedOnValue": "Adicionado {0}", - "Advanced": "Avançado", - "AirDate": "Data da exibição", - "Aired": "Exibido", - "Albums": "Álbuns", - "All": "Tudo", - "AllChannels": "Todos os canais", - "AllComplexFormats": "Todos os formatos complexos (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Todos os episódios", - "AllLanguages": "Todos os idiomas", - "AllowSeasonalThemes": "Permitir temas sazonais automáticos", - "AllowSeasonalThemesHelp": "Se ativado, temas sazonais irão sobrepor a configuração de temas.", - "AlwaysPlaySubtitles": "Sempre reproduzir legendas", - "AlwaysPlaySubtitlesHelp": "As legendas que combinarem com a preferência de idioma serão carregadas independente do idioma do áudio.", - "AnamorphicVideoNotSupported": "Vídeo anamórfico não suportado", - "AndroidUnlockRestoreHelp": "Para restaurar sua compra anterior, por favor certifique-se que está com a sessão aberta com a mesma conta Google (ou Amazon) que fez a compra originalmente. Certifique-se que a app store está ativada e que não está restringida por nenhum controle parental e também verifique que possui uma conexão de internet ativa. Você só terá que fazer isto uma vez para restaurar sua compra anterior.", - "AnyLanguage": "Qualquer idioma", - "Anytime": "A qualquer momento", - "AroundTime": "Em torno de {0}", - "Art": "Arte", - "Artists": "Artistas", - "AsManyAsPossible": "Quantos forem possíveis", - "Ascending": "Ascendente", - "AspectRatio": "Proporção da imagem", - "AttemptingWakeServer": "Tentando despertar o servidor. Por favor, aguarde...", - "AttributeNew": "Novo", - "AudioBitDepthNotSupported": "Profundidade de bit de áudio não suportada", - "AudioBitrateNotSupported": "Taxa de áudio não suportada", - "AudioChannelsNotSupported": "Canais de áudio não suportados", - "AudioCodecNotSupported": "Codec de áudio não suportado", - "AudioProfileNotSupported": "Perfil de áudio não suportado", - "AudioSampleRateNotSupported": "Taxa de sample de áudio não suportada", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Automático (baseado na configuração do idioma)", - "AutomaticallyConvertNewContent": "Converter novo conteúdo automaticamente", - "AutomaticallyConvertNewContentHelp": "Novo conteúdo adicionado a esta pasta será automaticamente convertido.", - "AutomaticallySyncNewContent": "Transferir novo conteúdo automaticamente", - "AutomaticallySyncNewContentHelp": "Novo conteúdo adicionado a esta pasta será automaticamente transferido para o dispositivo.", - "Backdrop": "Imagem de Fundo", - "Backdrops": "Imagens de Fundo", - "Banner": "Banner", - "BestFit": "Mais provável", - "BirthLocation": "Local de nascimento", - "Books": "Livros", - "Box": "Caixa", - "BoxRear": "Caixa (traseira)", - "Browse": "Navegar", - "BurnSubtitlesHelp": "Determina se o servidor deveria gravar as legendas no vídeo ao convertê-lo, dependendo do formato da legenda. Evitar a gravação da legenda irá melhorar a performance do servidor. Selecione Auto para gravar a imagem baseado nos formatos (ex. VOBSUB, PGS, SUB/IDX, etc.) assim como algumas legendas ASS/SSA.", - "ButtonCancel": "Cancelar", - "ButtonGotIt": "Feito", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Reproduzir Um Minuto", - "ButtonRestart": "Reiniciar", - "ButtonRestorePreviousPurchase": "Recuperar Compra", - "ButtonTryAgain": "Tente Novamente", - "ButtonUnlockPrice": "Desbloquear {0}", - "ButtonUnlockWithPurchase": "Desbloquear com Compra", - "CancelDownload": "Cancelar download", - "CancelRecording": "Cancelar gravação", - "CancelSeries": "Cancelar série", - "Categories": "Categorias", - "ChannelNameOnly": "Somente canal {0}", - "ChannelNumber": "Número do canal", - "CinemaModeConfigurationHelp": "O modo cinema traz a experiência do cinema diretamente para a sua sala, possibilitando reproduzir trailers e introduções personalizadas antes do filme principal.", - "CinemaModeFeatureDescription": "Modo Cinema oferece a você uma verdadeira experiência de cinema com trailers e intros customizados antes da funcionalidade.", - "CloudSyncFeatureDescription": "Sincronize sua mídia para a nuvem para backup, arquivamento e conversão fáceis.", - "Collections": "Coletâneas", - "ColorPrimaries": "Cores primárias", - "ColorSpace": "Espaço da cor", - "ColorTransfer": "Transferência da cor", - "CommunityRating": "Avaliação da Comunidade", - "Composer": "Compositor", - "ConfigureDateAdded": "Configure como a data de adição é determinada no painel do Servidor Jellyfin nas definições de Biblioteca", - "ConfirmDeleteImage": "Apagar imagem?", - "ConfirmDeleteItem": "Excluir este item o excluirá do sistema de arquivos e também da biblioteca de mídias. Deseja realmente continuar?", - "ConfirmDeleteItems": "Ao excluir estes itens você os excluirá do sistema de arquivos e de sua biblioteca de mídias. Deseja realmente continuar?", - "ConfirmDeletion": "Confirmar Exclusão", - "ConfirmEndPlayerSession": "Deseja realmente desligar o Jellyfin em {0}?", - "ConfirmRemoveDownload": "Remover download?", - "Connect": "Conectar", - "ContainerBitrateExceedsLimit": "A taxa de bits da mídia excede o limite.", - "ContainerNotSupported": "Container não suportado", - "Continue": "Continuar", - "ContinueInSecondsValue": "Continuar em {0} segundos.", - "ContinueWatching": "Continuar assistindo", - "Continuing": "Em Exibição", - "Convert": "Converter", - "ConvertItemLimitHelp": "Opcional. Definir um limite para o número de itens que serão convertidos.", - "ConvertUnwatchedVideosOnly": "Converter apenas vídeos não assistidos", - "ConvertUnwatchedVideosOnlyHelp": "Apenas vídeos não assistidos serão convertidos.", - "ConvertingDots": "Convertendo...", - "Countries": "Países", - "CriticRating": "Avaliação da Crítica", - "DateAdded": "Data da adição", - "DatePlayed": "Data da reprodução", - "Days": "Dias", - "Default": "Padrão", - "DefaultErrorMessage": "Ocorreu um erro ao processar o pedido. Por favor, tente novamente mais tarde.", - "DefaultSubtitlesHelp": "Legendas são carregadas com base nas configurações padrão e de legendas forçadas nos metadados embutidos. As preferências de idioma são consideradas quando existem múltiplas opções disponíveis.", - "Delete": "Excluir", - "DeleteMedia": "Excluir mídia", - "Depressed": "Deprimido", - "Descending": "Descendente", - "Desktop": "Desktop", - "DirectPlayError": "Erro de reprodução direta", - "DirectPlaying": "Reprodução direta", - "DirectStreamHelp1": "A mídia é compatível com o dispositivo, independente da resolução e tipo de mídia (H.264, AC3, etc.), mas está em um contaminar incompatível (.mkv, .avi, .wmv, etc.). O vídeo será reempacotado em tempo real antes de transmitir para o dispositivo.", - "DirectStreamHelp2": "A Transmissão direta de um arquivo usa pouco processamento sem perda de qualidade do vídeo.", - "DirectStreaming": "Streaming direta", - "Director": "Diretor", - "DirectorValue": "Diretor: {0}", - "DirectorsValue": "Diretores: {0}", - "Disc": "Disco", - "Disconnect": "Desconectar", - "Dislike": "Não curti", - "Display": "Exibir", - "DisplayInMyMedia": "Exibir na tela início", - "DisplayInOtherHomeScreenSections": "Exibir nas seções da tela início como mídia recente e continuar assistindo", - "DisplayMissingEpisodesWithinSeasons": "Exibir episódios que faltam dentro das temporadas", - "DisplayMissingEpisodesWithinSeasonsHelp": "Isto também deve ser ativado para as bibliotecas de TV na configuração do Servidor Jellyfin.", - "DisplayModeHelp": "Selecione o tipo de tela para executar o Jellyfin.", - "DoNotRecord": "Não gravar", - "Down": "Para baixo", - "Download": "Download", - "DownloadItemLimitHelp": "Opcional. Definir um limite para o número de itens que serão baixados.", - "Downloaded": "Transferido(s)", - "Downloading": "Transferindo", - "DownloadingDots": "Transferindo...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Sombra", - "DvrFeatureDescription": "Agendar gravações individuais de TV ao vivo, gravações de séries e mais com o Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requer uma assinatura ativa do Jellyfin Premiere", - "Edit": "Editar", - "EditImages": "Editar imagens", - "EditMetadata": "Editar metadados", - "EditSubtitles": "Editar legendas", - "EnableBackdrops": "Ativar imagens de fundo", - "EnableBackdropsHelp": "Se ativadas, imagens de fundo serão exibidas ao fundo de algumas páginas ao navegar pela biblioteca.", - "EnableCinemaMode": "Ativar modo cinema", - "EnableColorCodedBackgrounds": "Habilitar cores de fundo por código", - "EnableDisplayMirroring": "Ativar espelhamento de tela", - "EnableExternalVideoPlayers": "Ativar reprodutores de vídeo externos", - "EnableExternalVideoPlayersHelp": "Um menu do reprodutor externo será exibido ao iniciar a reprodução do vídeo.", - "EnableNextVideoInfoOverlay": "Ativar as informações do próximo vídeo durante a reprodução", - "EnableNextVideoInfoOverlayHelp": "Ao final de um vídeo, exibe informações sobre o próximo vídeo que está na lista de reprodução.", - "EnableThemeSongs": "Ativar músicas-tema", - "EnableThemeSongsHelp": "Se ativadas, músicas-tema serão reproduzidas em segundo plano ao navegar pela biblioteca.", - "EnableThemeVideos": "Ativar músicas-tema", - "EnableThemeVideosHelp": "Se ativadas, músicas-tema serão reproduzidas em segundo plano ao navegar pela biblioteca.", - "Ended": "Finalizada", - "EndsAtValue": "Termina às {0}", - "Episodes": "Episódios", - "Error": "Erro", - "ErrorAddingGuestAccount1": "Ocorreu um erro ao adicionar a conta do Jellyfin Connect. Os seus convidados criaram uma conta do Jellyfin? Eles podem registrar-se em {0}.", - "ErrorAddingGuestAccount2": "Se ainda tiver problemas, por favor envie uma email para {0} e inclua seu endereço de email, assim como os deles.", - "ErrorAddingJellyfinConnectAccount1": "Ocorreu um erro ao adicionar a conta do Jellyfin Connect. Você criou uma conta do Jellyfin? Registra-se em {0}.", - "ErrorAddingJellyfinConnectAccount2": "Se ainda tiver problemas, por favor envie uma email para {0} a partir do endereço de email usado na conta do Jellyfin.", - "ErrorConnectServerUnreachable": "Ocorreu um erro ao executar a operação solicitada. Seu servidor não pode contactar nosso Jellyfin Connect Server em {0}. Por favor, verifique se seu servidor possui uma conexão de internet ativa e se as comunicações estão liberadas pelo firewall ou software de segurança instalados.", - "ErrorDeletingItem": "Ocorreu um erro ao excluir o item do Servidor Jellyfin. Por favor, verifique se o Servidor Jellyfin possui acesso de gravação na pasta de mídia e tente novamente,", - "ErrorReachingJellyfinConnect": "Ocorreu um erro ao acessar o servidor do Jellyfin Connect. Por favor, verifique se possui uma conexão com a internet e tente novamente.", - "ErrorRemovingJellyfinConnectAccount": "Ocorreu um erro ao remover a conta do Jellyfin Connect. Por favor, verifique se possui conexão com a internet e tente novamente.", - "ExtraLarge": "Extra grande", - "Extras": "Extras", - "Favorite": "Favorito", - "Favorites": "Favoritos", - "FeatureRequiresJellyfinPremiere": "Este recurso requer uma subscrição ativa do Jellyfin Premiere", - "Features": "Recursos", - "File": "Arquivo", - "Fill": "Preencher", - "Filters": "Filtros", - "Folders": "Pastas", - "FormatValue": "Formato: {0}", - "FreeAppsFeatureDescription": "Aproveite acesso grátis a apps Jellyfin para seus dispositivos.", - "Friday": "Sexta-feira", - "GenreValue": "Gênero: {0}", - "Genres": "Gêneros", - "GenresValue": "Gêneros: {0}", - "GroupBySeries": "Agrupar por séries", - "GroupVersions": "Agrupar versões", - "GuestStar": "Convidado Especial", - "GuestUserNotFound": "Usuário não encontrado. Por favor, verifique que o nome esteja correto e tente novamente, ou tente digitar o endereço de email deles.", - "Guide": "Guia", - "HDPrograms": "Programas em HD", - "HeaderActiveRecordings": "Gravações Ativas", - "HeaderAddToCollection": "Adicionar à Coletânea", - "HeaderAddToPlaylist": "Adicionar à Lista de Reprodução", - "HeaderAddUpdateImage": "Adicionar/Atualizar Imagem", - "HeaderAlbumArtists": "Artistas do Álbum", - "HeaderAlreadyPaid": "Já Pagou?", - "HeaderAppearsOn": "Aparece em", - "HeaderAudioBooks": "Livros de Áudio", - "HeaderAudioSettings": "Ajustes de Áudio", - "HeaderBecomeProjectSupporter": "Obter Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefícios do Jellyfin Premiere", - "HeaderCancelRecording": "Cancelar Gravação", - "HeaderCancelSeries": "Cancelar Série", - "HeaderCinemaMode": "Modo Cinema", - "HeaderCloudSync": "Sincronização na Nuvem", - "HeaderConfirmRecordingCancellation": "Confirmar Cancelamento da Gravação", - "HeaderContinueListening": "Continuar Escutando", - "HeaderContinueWatching": "Continuar Assistindo", - "HeaderConvertYourRecordings": "Converter suas Gravações", - "HeaderCustomizeHomeScreen": "Personalizar Tela Início", - "HeaderDeleteItem": "Excluir item", - "HeaderDeleteItems": "Excluir Itens", - "HeaderDisplaySettings": "Ajustes de Exibição", - "HeaderDownloadSettings": "Configurações de Download", - "HeaderEditImages": "Editar Imagens", - "HeaderEnabledFields": "Campos Ativados", - "HeaderEnabledFieldsHelp": "Desmarque um campo para bloqueá-lo e evitar que seus dados sejam alterados.", - "HeaderExternalIds": "Ids Externos:", - "HeaderFavoriteAlbums": "Álbuns Favoritos", - "HeaderFavoriteArtists": "Artistas Favoritos", - "HeaderFavoriteCollections": "Coletâneas Favoritas", - "HeaderFavoriteEpisodes": "Episódios Favoritos", - "HeaderFavoriteGames": "Jogos Favoritos", - "HeaderFavoriteMovies": "Filmes Favoritos", - "HeaderFavoritePlaylists": "Listas de Reprodução Favoritas", - "HeaderFavoriteShows": "Séries Favoritas", - "HeaderFavoriteSongs": "Músicas Favoritas", - "HeaderFavoriteVideos": "Vídeos Favoritos", - "HeaderFreeApps": "Apps Jellyfin grátis", - "HeaderHomeScreen": "Tela Início", - "HeaderIdentifyItemHelp": "Digite um ou mais critérios de busca. Exclua o critério para aumentar os resultados da busca.", - "HeaderInvitationSent": "Convite Enviado", - "HeaderJellyfinAccountAdded": "Conta do Jellyfin Adicionada", - "HeaderJellyfinAccountRemoved": "Conta do Jellyfin Removida", - "HeaderKeepRecording": "Continuar Gravando", - "HeaderKeepSeries": "Manter Série", - "HeaderLatestChannelItems": "Itens de Canais Recentes", - "HeaderLatestChannelMedia": "Itens de Canais Recentes", - "HeaderLatestFrom": "Mais recentes de {0}", - "HeaderLatestMedia": "Mídias Recentes", - "HeaderLatestRecordings": "Gravações Recentes", - "HeaderLearnMore": "Saiba Mais", - "HeaderLibraryFolders": "Pastas da Biblioteca", - "HeaderLibraryOrder": "Ordem da Biblioteca", - "HeaderMetadataSettings": "Ajustes dos Metadados", - "HeaderMusicQuality": "Qualidade da Música:", - "HeaderMyDevice": "Meu Dispositivo", - "HeaderMyDownloads": "Meus Downloads", - "HeaderMyMedia": "Minha Mídia", - "HeaderMyMediaSmall": "Minha Mídia (pequeno)", - "HeaderNewRecording": "Nova Gravação", - "HeaderNextEpisodePlayingInValue": "Novo Episódio Reproduzindo em {0}", - "HeaderNextUp": "Próximos", - "HeaderNextVideoPlayingInValue": "Próximo Vídeo Reproduzindo em {0}", - "HeaderOfflineDownloads": "Mídia Offline", - "HeaderOfflineDownloadsDescription": "Download sua mídia para seus dispositivos para uso offline fácil.", - "HeaderOnNow": "Em Exibição", - "HeaderPhotoAlbums": "Álbuns de Fotos", - "HeaderPlayMyMedia": "Reproduzir minha Mídia", - "HeaderPlayOn": "Reproduzir em", - "HeaderPlaybackError": "Erro na Reprodução", - "HeaderRecordingOptions": "Opções de Gravação", - "HeaderRemoteControl": "Controle Remoto", - "HeaderRestartingJellyfinServer": "Reiniciando o Servidor Jellyfin", - "HeaderSaySomethingLike": "Diga Alguma Coisa Como...", - "HeaderSecondsValue": "{0} Segundos", - "HeaderSelectDate": "Selecionar Data", - "HeaderSeriesOptions": "Opções da Série", - "HeaderSeriesStatus": "Status das Séries", - "HeaderSpecialEpisodeInfo": "Informação do Episódio Especial", - "HeaderStartNow": "Iniciar Agora", - "HeaderStopRecording": "Parar Gravação", - "HeaderSubtitleAppearance": "Aparência da Legenda", - "HeaderSubtitleSettings": "Ajustes de Legenda", - "HeaderSyncRequiresSub": "O Download requer uma subscrição ativa do Jellyfin Premiere.", - "HeaderTermsOfPurchase": "Termos de Compra", - "HeaderTryPlayback": "Testar Reprodução", - "HeaderUnlockFeature": "Desbloquear Funcionalidade", - "HeaderUploadImage": "Carregar Imagem", - "HeaderVideoQuality": "Qualidade do Vídeo", - "HeaderVideoType": "Tipo de Vídeo", - "HeaderWaitingForWifi": "Esperando por Wifi", - "HeaderWakeServer": "Despertar Servidor", - "HeaderYouSaid": "Você Disse...", - "Help": "Ajuda", - "Hide": "Ocultar", - "HideWatchedContentFromLatestMedia": "Ocultar conteúdo assistido das mídias recentes", - "Home": "Início", - "Horizontal": "Horizontal", - "HowDidYouPay": "Como você pagou?", - "IHaveJellyfinPremiere": "Eu tenho Jellyfin Premiere", - "IPurchasedThisApp": "Eu comprei este app", - "Identify": "Identificar", - "Images": "Imagens", - "ImdbRating": "Avaliação IMDb", - "InstallingPackage": "Instalando {0}", - "InstantMix": "Mix instântaneo", - "InterlacedVideoNotSupported": "Vídeo interlaçado não suportado", - "ItemCount": "{0} itens", - "Items": "itens", - "KeepDownload": "Manter transferência", - "KeepOnDevice": "Manter no dispositivo", - "Kids": "Crianças", - "Label3DFormat": "Formato 3D:", - "LabelAirDays": "Dias da exibição:", - "LabelAirTime": "Horário:", - "LabelAirsAfterSeason": "Exibido depois da temporada:", - "LabelAirsBeforeEpisode": "Exibido antes do episódio:", - "LabelAirsBeforeSeason": "Exibido antes da temporada:", - "LabelAlbum": "Álbum:", - "LabelAlbumArtists": "Artistas do Álbum:", - "LabelArtists": "Artistas:", - "LabelArtistsHelp": "Separar múltiplos usando ;", - "LabelAudio": "Áudio:", - "LabelAudioLanguagePreference": "Áudio preferido para exibição:", - "LabelBirthDate": "Data de nascimento:", - "LabelBirthYear": "Ano de nascimento:", - "LabelBitrateMbps": "Taxa (Mbps):", - "LabelBurnSubtitles": "Gravar legendas:", - "LabelChannels": "Canais:", - "LabelCollection": "Coletânea:", - "LabelCommunityRating": "Avaliação da comunidade:", - "LabelContentType": "Tipo de conteúdo:", - "LabelConvertTo": "Converter para:", - "LabelCountry": "País:", - "LabelCriticRating": "Avaliação da crítica:", - "LabelCustomRating": "Classificação personalizada:", - "LabelDashboardTheme": "Tema do painel do servidor:", - "LabelDateAdded": "Data de adição:", - "LabelDateTimeLocale": "Hora local:", - "LabelDeathDate": "Data da morte:", - "LabelDefaultScreen": "Tela padrão:", - "LabelDiscNumber": "Número do disco:", - "LabelDisplayLanguage": "Idioma para exibição:", - "LabelDisplayLanguageHelp": "A tradução do Jellyfin é um projeto em andamento.", - "LabelDisplayMode": "Mode de exibição:", - "LabelDisplayOrder": "Ordem de exibição:", - "LabelDropImageHere": "Soltar a imagem aqui, ou clicar para procurar.", - "LabelDropShadow": "Sombra:", - "LabelDynamicExternalId": "Id de {0}:", - "LabelEmailAddress": "Endereço de E-mail:", - "LabelEndDate": "Data final:", - "LabelEpisodeNumber": "Número do episódio:", - "LabelFont": "Fonte:", - "LabelHomeNetworkQuality": "Qualidade da rede local:", - "LabelHomeScreenSectionValue": "Seção {0} da tela Início:", - "LabelImageType": "Tipo de imagem:", - "LabelInternetQuality": "Qualidade da internet:", - "LabelItemLimit": "Limite de itens:", - "LabelKeep:": "Manter:", - "LabelKeepUpTo": "Manter até:", - "LabelLanguage": "Idioma:", - "LabelLockItemToPreventChanges": "Bloquear este item para evitar alterações futuras", - "LabelMaxChromecastBitrate": "Qualidade para streaming do chromecast:", - "LabelMetadataDownloadLanguage": "Idioma preferido para download:", - "LabelName": "Nome:", - "LabelNumber": "Número:", - "LabelOriginalAspectRatio": "Proporção da imagem original:", - "LabelOriginalTitle": "Título original:", - "LabelOverview": "Sinopse:", - "LabelParentNumber": "Número do superior:", - "LabelParentalRating": "Classificação etária:", - "LabelPath": "Local:", - "LabelPersonRole": "Personagem:", - "LabelPersonRoleHelp": "Exemplo: motorista do carrinho de sorvete", - "LabelPlaceOfBirth": "Local de nascimento:", - "LabelPlayDefaultAudioTrack": "Reproduzir a faixa de áudio padrão, independente do idioma", - "LabelPlaylist": "Lista de Reprodução:", - "LabelPreferredSubtitleLanguage": "Idioma de legendas preferido:", - "LabelProfile": "Perfil:", - "LabelQuality": "Qualidade:", - "LabelReasonForTranscoding": "Motivo da transcodificação:", - "LabelRecord": "Gravar:", - "LabelRefreshMode": "Mode de atualização:", - "LabelReleaseDate": "Data do lançamento:", - "LabelRuntimeMinutes": "Duração (minutos):", - "LabelScreensaver": "Protetor de Tela:", - "LabelSeasonNumber": "Número da temporada:", - "LabelSelectFolderGroups": "Agrupar automaticamente o conteúdo das seguintes pastas dentro das visualizações como Filmes, Músicas e TV:", - "LabelSelectFolderGroupsHelp": "Pastas que não estão marcadas serão exibidas em sua própria visualização.", - "LabelShortOverview": "Sinopse curta:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Tamanho do intervalo para retroceder", - "LabelSkipForwardLength": "Tamanho do intervalo para avançar", - "LabelSortBy": "Classificar por:", - "LabelSortOrder": "Forma de classificar:", - "LabelSortTitle": "Título para ordenação:", - "LabelSoundEffects": "Efeitos sonoros:", - "LabelSource": "Fonte:", - "LabelStartWhenPossible": "Iniciar quando possível:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Parar quando possível:", - "LabelSubtitlePlaybackMode": "Modo de legendas:", - "LabelSubtitles": "Legendas:", - "LabelSyncJobName": "Nome da tarefa de sincronização:", - "LabelSyncNoTargetsHelp": "Parece que você não possui nenhuma app que suporta o download offline.", - "LabelSyncTo": "Sincronizar para:", - "LabelTVHomeScreen": "Tela início do modo TV:", - "LabelTagline": "Slogan:", - "LabelTextBackgroundColor": "Cor de fundo do texto:", - "LabelTextColor": "Cor do texto:", - "LabelTextSize": "Tamanho do texto:", - "LabelTheme": "Tema:", - "LabelTitle": "Título:", - "LabelTrackNumber": "Número da faixa:", - "LabelType": "Tipo:", - "LabelVersion": "Versão:", - "LabelVideo": "Vídeo:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Cor de fundo do texto:", - "LabelYear": "Ano:", - "Large": "Grande", - "LatestFromLibrary": "Mais Recentes {0}", - "LearnHowYouCanContribute": "Saiba como você pode contribuir.", - "LearnMore": "Saiba mais", - "Like": "Curti", - "LinksValue": "Links: {0}", - "List": "Lista", - "Live": "Ao vivo", - "LiveBroadcasts": "Broadcasts ao vivo", - "LiveTV": "TV ao Vivo", - "LiveTvFeatureDescription": "Assistir TV ao vivo em qualquer app Jellyfin com um sintonizador de TV compatível, instalado em seu servidor Jellyfin.", - "LiveTvRequiresUnlock": "A TV ao vivo exige uma assinatura ativa do Jellyfin Premiere.", - "Logo": "Logo", - "ManageRecording": "Gerenciar gravação", - "MarkPlayed": "Marcar como reproduzido", - "MarkUnplayed": "Marcar como não-reproduzido", - "MarkWatched": "Marcar como assisitido", - "MediaIsBeingConverted": "A mídia está sendo convertida para um formato que é compatível com o dispositivo que reproduz a mídia.", - "Medium": "Média", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Uma subscrição ativa do Jellyfin Premiere é requerida para criar a gravação automatizada de séries.", - "MessageAreYouSureDeleteSubtitles": "Deseja realmente excluir este arquivo de legendas?", - "MessageConfirmRecordingCancellation": "Cancelar gravação?", - "MessageDownloadQueued": "Download enfileirado.", - "MessageFileReadError": "Ocorreu um erro ao ler o arquivo. Por favor, tente novamente.", - "MessageIfYouBlockedVoice": "Se você negou o acesso de voz ao app, você necessitará reconfigurar antes de tentar novamente.", - "MessageInvitationSentToNewUser": "Um email foi enviado para {0}, convidando-os a se registrarem no Jellyfin.", - "MessageInvitationSentToUser": "Um email foi enviado para {0}, convidando-os para aceitar seu convite.", - "MessageItemSaved": "Item salvo.", - "MessageItemsAdded": "Itens adicionados.", - "MessageJellyfinAccontRemoved": "A conta do Jellyfin foi removida para este usuário", - "MessageJellyfinAccountAdded": "A conta do Jellyfin foi adicionada para este usuário.", - "MessageLeaveEmptyToInherit": "Deixar em branco para herdar os ajustes de um item superior, ou o valor padrão global", - "MessageNoDownloadsFound": "Nenhum download offline. Baixe sua mídia para usá-la offline clicando em Download no app.", - "MessageNoServersAvailableToConnect": "Nenhum servidor disponível para se conectar. Se foi convidado para compartilhar um servidor, aceite abaixo ou clicando no link no email.", - "MessageNoSyncJobsFound": "Nenhum download encontrado. Crie tarefas de download usando os botões Download encontrados no app.", - "MessagePendingJellyfinAccountAdded": "A conta do Jellyfin foi adicionada para este usuário. Um email será enviado para o dono da conta. O convite precisará ser confirmado clicando no link dentro do email.", - "MessagePlayAccessRestricted": "A reprodução para este conteúdo está restrita. Por favor, contate o administrador do Servidor Jellyfin para mais informações.", - "MessageToValidateSupporter": "Se tiver uma assinatura ativa do Jellyfin Premiere, assegure-se que configurou o Jellyfin Premiere no Painel do Servidor Jellyfin, que pode ser acessado clicando Jellyfin Premiere no menu principal.", - "MessageUnlockAppWithPurchaseOrSupporter": "Desbloqueie esta funcionalidade com uma pequena compra única, ou com uma assinatura ativa do Jellyfin Premiere.", - "MessageUnlockAppWithSupporter": "Desbloqueie esta funcionalidade com uma assinatura ativa do Jellyfin Premiere.", - "MessageWeDidntRecognizeCommand": "Desculpe, não reconhecemos este comando.", - "MinutesAfter": "minutos após", - "MinutesBefore": "minutos antes de", - "Mobile": "Celular / Tablet", - "Monday": "Segunda-feira", - "More": "Mais", - "MoveLeft": "Mover para esquerda", - "MoveRight": "Mover para direita", - "Movies": "Filmes", - "MySubtitles": "Minhas Legendas", - "Name": "Nome", - "NewCollection": "Nova Coletânea", - "NewCollectionHelp": "Coletâneas permitem que você crie grupos personalizados de filmes e outros conteúdos da biblioteca.", - "NewCollectionNameExample": "Exemplo: Coletânea Star Wars", - "NewEpisodes": "Novos episódios", - "NewEpisodesOnly": "Apenas novos episódios", - "News": "Notícias", - "Next": "Próximo", - "No": "Não", - "NoItemsFound": "Nenhum item encontrado.", - "NoSubtitleSearchResultsFound": "Nenhum resultado encontrado.", - "NoSubtitles": "Sem Legenda", - "NoSubtitlesHelp": "Legendas não serão carregadas por padrão. Elas podem ser carregadas manualmente durante a reprodução.", - "None": "Nenhum(a)", - "Normal": "Normal", - "Off": "Desligado", - "OneChannel": "Um canal", - "OnlyForcedSubtitles": "Apenas legendas forçadas", - "OnlyForcedSubtitlesHelp": "Apenas legendas marcadas como forçadas serão carregadas.", - "OnlyImageFormats": "Apenas formatos de imagens (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Abrir", - "OptionNew": "Nova...", - "Original": "Original", - "OriginalAirDateValue": "Data de exibição original: {0}", - "Overview": "Sinopse", - "PackageInstallCancelled": "Instalação de {0} cancelada.", - "PackageInstallCompleted": "Instalação de {0} concluída.", - "PackageInstallFailed": "Instalação de {0} falhou.", - "ParentalRating": "Classificação Etária", - "People": "Pessoas", - "PerfectMatch": "Combinação perfeita", - "Photos": "Fotos", - "PlaceFavoriteChannelsAtBeginning": "Colocar canais favoritos no início", - "Play": "Reproduzir", - "PlayAllFromHere": "Reproduzir todas a partir daqui", - "PlayCount": "Número de Reproduções", - "PlayFromBeginning": "Reproduzir do início", - "PlayNext": "Reproduzir próximo", - "PlayNextEpisodeAutomatically": "Reproduzir próximo episódio automaticamente", - "PlaybackErrorNoCompatibleStream": "Não existem streams compatíveis. Por favor, tente novamente mais tarde ou contate o administrador do sistema para mais detalhes.", - "PlaybackErrorNotAllowed": "Você não está autorizado a reproduzir este conteúdo. Por favor, contacte seu administrador do sistema para mais detalhes.", - "PlaybackErrorPlaceHolder": "Por favor, insira o disco para reproduzir este vídeo.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Reproduzido", - "Playlists": "Listas de Reprodução", - "PleaseEnterNameOrId": "Por favor, digite um nome ou Id externo.", - "PleaseRestartServerName": "Por favor reinicie o Servidor Jellyfin - {0}.", - "PleaseSelectDeviceToSyncTo": "Por favor, selecione um dispositivo para transferir.", - "PleaseSelectTwoItems": "Por favor selecione pelo menos dois itens.", - "Premiere": "Premiere", - "Premieres": "Estréias", - "Previous": "Anterior", - "Primary": "Capa", - "PrivacyPolicy": "Política de privacidade", - "Producer": "Produtor", - "ProductionLocations": "Locais de produção", - "Programs": "Programas", - "PromoConvertRecordingsToStreamingFormat": "Converter automaticamente gravações para um formato amigável para streaming com Jellyfin Premiere. Gravações serão convertidas em tempo real para MP4 ou MKV, baseado nas configurações do Servidor Jellyfin.", - "Quality": "Qualidade", - "QueueAllFromHere": "Enfileirar todas a partir daqui", - "Raised": "Levantada", - "RecentlyWatched": "Assistido recentemente", - "Record": "Gravar", - "RecordSeries": "Gravar série", - "RecordingCancelled": "Gravação cancelada.", - "RecordingScheduled": "Gravação agendada.", - "Recordings": "Gravações", - "RefFramesNotSupported": "Número de quadros de referência de vídeo não suportado", - "Refresh": "Atualizar", - "RefreshDialogHelp": "Os metadados são atualizados com bases nas definições e nos serviços de internet que estão ativos no painel do Servidor Jellyfin.", - "RefreshMetadata": "Atualizar metadados", - "RefreshQueued": "Atualização iniciada.", - "Reject": "Rejeitar", - "ReleaseDate": "Data de lançamento", - "RemoveDownload": "Remover download", - "RemoveFromCollection": "Remover da coleção", - "RemoveFromPlaylist": "Remover da lista de reprodução", - "RemovingFromDevice": "Removendo do dispositivo", - "Repeat": "Repetir", - "RepeatAll": "Repetir todas", - "RepeatEpisodes": "Repetir episódios", - "RepeatMode": "Modo de repetição", - "RepeatOne": "Repetir uma", - "ReplaceAllMetadata": "Substituir todos os metadados", - "ReplaceExistingImages": "Substituir imagens existentes", - "RestartPleaseWaitMessage": "Por favor, aguarde enquanto o Servidor Jellyfin reinicia. Isto pode levar um ou dois minutos.", - "ResumeAt": "Retomar de {0}", - "Retry": "Tentar Novamente", - "RunAtStartup": "Executar ao iniciar", - "Runtime": "Duração", - "Saturday": "Sábado", - "Save": "Salvar", - "ScanForNewAndUpdatedFiles": "Rastrear por arquivos novos e atualizados", - "Schedule": "Agendar", - "Screenshot": "Imagem da tela", - "Screenshots": "Screenshots", - "Search": "Busca", - "SearchForCollectionInternetMetadata": "Buscar artwork e metadados na internet", - "SearchForMissingMetadata": "Buscar por metadados que faltam", - "SearchForSubtitles": "Buscar Legendas", - "SearchResults": "Resultados da Busca", - "SecondaryAudioNotSupported": "Mudança de trilha de áudio não suportada", - "SeriesCancelled": "Série cancelada.", - "SeriesDisplayOrderHelp": "Ordenar episódios por data de exibição, ordem de dvd ou números absolutos.", - "SeriesRecordingScheduled": "Gravação de série agendada.", - "SeriesSettings": "Configurações da série", - "SeriesYearToPresent": "{0} - Presente", - "ServerNameIsRestarting": "Servidor Jellyfin - {0} está reiniciando.", - "ServerNameIsShuttingDown": "Servidor Jellyfin - {0} está desligando.", - "ServerUpdateNeeded": "Este Servidor Jellyfin precisa ser atualizado. Para fazer download da versão mais recente, por favor visite {0}", - "Settings": "Ajustes", - "SettingsSaved": "Configurações salvas.", - "Share": "Compartilhar", - "ShowIndicatorsFor": "Mostrar indicadores para:", - "ShowTitle": "Exibir título", - "ShowYear": "Exibir ano", - "Shows": "Séries", - "Shuffle": "Aleatório", - "SkipEpisodesAlreadyInMyLibrary": "Não gravar episódios que já estejam em minha biblioteca", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episódios serão comparados utilizando temporada e números de episódios, quando disponíveis.", - "Small": "Pequena", - "SmallCaps": "Maiúsculas", - "Smaller": "Menor", - "Smart": "Inteligente", - "SmartSubtitlesHelp": "As legendas que combinarem com a preferência do idioma serão carregadas quando o áudio estiver em um idioma estrangeiro.", - "Songs": "Músicas", - "Sort": "Ordenar", - "SortByValue": "Classificar por {0}", - "SortChannelsBy": "Ordenar canais por:", - "SortName": "Nome para ordenação", - "Sports": "Esportes", - "StatsForNerds": "Estatísticas para nerds", - "StopRecording": "Parar gravação", - "Studios": "Estúdios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Estas configurações também se aplicam para qualquer reprodução do Chromecast para este dispositivo.", - "SubtitleAppearanceSettingsDisclaimer": "Estes ajustes não serão aplicados às legendas gráficas (PGS, DVD, etc) ou às legendas que têm seus próprios estilos embutidos (ASS/SSA).", - "SubtitleCodecNotSupported": "Formato da legenda não suportado", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Legendas", - "Suggestions": "Sugestões", - "Sunday": "Domingo", - "Sync": "Sincronizar", - "SyncJobItemStatusCancelled": "Cancelado", - "SyncJobItemStatusConverting": "Convertendo", - "SyncJobItemStatusFailed": "Falha", - "SyncJobItemStatusQueued": "Enfileirado", - "SyncJobItemStatusReadyToTransfer": "Pronto para Transferir", - "SyncJobItemStatusRemovedFromDevice": "Removido do dispositivo", - "SyncJobItemStatusSynced": "Baixado", - "SyncJobItemStatusSyncedMarkForRemoval": "Removendo do dispositivo", - "SyncJobItemStatusTransferring": "Transferindo", - "SyncUnwatchedVideosOnly": "Transferir apenas vídeos não assistidos", - "SyncUnwatchedVideosOnlyHelp": "Apenas vídeos não assistidos serão transferidos, e os vídeos serão removidos do dispositivo assim que forem assistidos.", - "SyncingDots": "Sincronizando...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Termos de uso", - "ThankYouForTryingEnjoyOneMinute": "Por favor aproveite um minuto de reprodução. Obrigado por testar Jellyfin.", - "ThemeSongs": "Músicas Tema", - "ThemeVideos": "Vídeos Tema", - "TheseSettingsAffectSubtitlesOnThisDevice": "Estes ajustes afetarão as legendas neste dispositivo", - "Thumb": "Ícone", - "Thursday": "Quinta-feira", - "TrackCount": "{0} faixas", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcodificação", - "TryMultiSelect": "Experimentar a Seleção Múltipla", - "TryMultiSelectMessage": "Para editar itens múltiplos de mídia, basta clicar e segurar qualquer capa e selecionar os itens que gostaria de gerenciar. Experimente!", - "Tuesday": "Terça-feira", - "Uniform": "Uniforme", - "UnlockGuide": "Desbloquear Guia", - "Unplayed": "Não Reproduzido", - "Unrated": "Não-classificado", - "UntilIDelete": "Até eu excluir", - "UntilSpaceNeeded": "Até o espaço necessário", - "Up": "Para cima", - "Upload": "Carregar", - "ValueAlbumCount": "{0} álbuns", - "ValueDiscNumber": "Disco {0}", - "ValueEpisodeCount": "{0} episódios", - "ValueGameCount": "{0} jogos", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} filmes", - "ValueMusicVideoCount": "{0} vídeos musicais", - "ValueOneAlbum": "1 álbum", - "ValueOneEpisode": "1 episódio", - "ValueOneGame": "1 jogo", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 filme", - "ValueOneMusicVideo": "1 vídeo musical", - "ValueOneSeries": "1 série", - "ValueOneSong": "1 música", - "ValueSeconds": "{0} segundos", - "ValueSeriesCount": "{0} séries", - "ValueSongCount": "{0} músicas", - "ValueSpecialEpisodeName": "Especial - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Profundidade de bit de vídeo não suportada", - "VideoCodecNotSupported": "Codec de vídeo não suportado", - "VideoFramerateNotSupported": "Taxa do vídeo não suportada", - "VideoLevelNotSupported": "Nível do vídeo não suportado", - "VideoProfileNotSupported": "Perfil de vídeo não suportado", - "VideoRange": "Faixa de vídeo", - "VideoResolutionNotSupported": "Resolução de vídeo não suportada", - "ViewAlbum": "Ver álbum", - "ViewArtist": "Ver artista", - "VoiceInput": "Entrada de voz", - "WakeServer": "Acordar servidor", - "WakeServerError": "Pacotes de rede para despertar foram enviados para seu servidor, mas não foi possível conectar ao seu Servidor Jellyfin. Sua máquina pode necessitar um pouco mais de tempo para despertar, ou o Servidor Jellyfin pode não estar rodando na máquina.", - "WakeServerSuccess": "Deu certo!", - "Watched": "Assistido(s)", - "Wednesday": "Quarta-feira", - "WifiRequiredToDownload": "É necessária uma conexão Wifi para continuar a transferir.", - "Writer": "Escritor", - "Yes": "Sim" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "Desbloqueie esta funcionalidade com uma pequena compra \u00fanica, ou com uma assinatura ativa do Emby Premiere.", + "MessageUnlockAppWithSupporter": "Desbloqueie esta funcionalidade com uma assinatura ativa do Emby Premiere.", + "MessageToValidateSupporter": "Se tiver uma assinatura ativa do Emby Premiere, assegure-se que configurou o Emby Premiere no Painel do Servidor Emby, que pode ser acessado clicando Emby Premiere no menu principal.", + "ValueSpecialEpisodeName": "Especial - {0}", + "Share": "Compartilhar", + "Add": "Adicionar", + "ServerUpdateNeeded": "Este Servidor Emby precisa ser atualizado. Para fazer download da vers\u00e3o mais recente, por favor visite {0}", + "LiveTvRequiresUnlock": "A TV ao vivo exige uma assinatura ativa do Emby Premiere.", + "AttributeNew": "Novo", + "Premiere": "Premiere", + "Live": "Ao vivo", + "Repeat": "Repetir", + "TrackCount": "{0} faixas", + "ItemCount": "{0} itens", + "OriginalAirDateValue": "Data de exibi\u00e7\u00e3o original: {0}", + "EndsAtValue": "Termina \u00e0s {0}", + "HeaderSelectDate": "Selecionar Data", + "Watched": "Assistido(s)", + "AirDate": "Data da exibi\u00e7\u00e3o", + "Played": "Reproduzido", + "ButtonOk": "Ok", + "ButtonCancel": "Cancelar", + "AccessRestrictedTryAgainLater": "O acesso est\u00e1 atualmente restrito. Por favor, tente novamente mais tarde.", + "ButtonGotIt": "Feito", + "ButtonRestart": "Reiniciar", + "RecordingCancelled": "Grava\u00e7\u00e3o cancelada.", + "SeriesCancelled": "S\u00e9rie cancelada.", + "RecordingScheduled": "Grava\u00e7\u00e3o agendada.", + "SeriesRecordingScheduled": "Grava\u00e7\u00e3o de s\u00e9rie agendada.", + "HeaderNewRecording": "Nova Grava\u00e7\u00e3o", + "WakeServer": "Acordar servidor", + "HeaderWakeServer": "Despertar Servidor", + "AttemptingWakeServer": "Tentando despertar o servidor. Por favor, aguarde...", + "WakeServerSuccess": "Deu certo!", + "HeaderCustomizeHomeScreen": "Personalizar Tela In\u00edcio", + "WakeServerError": "Pacotes de rede para despertar foram enviados para seu servidor, mas n\u00e3o foi poss\u00edvel conectar ao seu Servidor Emby. Sua m\u00e1quina pode necessitar um pouco mais de tempo para despertar, ou o Servidor Emby pode n\u00e3o estar rodando na m\u00e1quina.", + "Sunday": "Domingo", + "Monday": "Segunda-feira", + "Tuesday": "Ter\u00e7a-feira", + "Wednesday": "Quarta-feira", + "Thursday": "Quinta-feira", + "Friday": "Sexta-feira", + "Saturday": "S\u00e1bado", + "Days": "Dias", + "SortByValue": "Classificar por {0}", + "LabelSortBy": "Classificar por:", + "LabelSortOrder": "Forma de classificar:", + "HeaderPhotoAlbums": "\u00c1lbuns de Fotos", + "Photos": "Fotos", + "HeaderAppearsOn": "Aparece em", + "List": "Lista", + "RecordSeries": "Gravar s\u00e9rie", + "HeaderCinemaMode": "Modo Cinema", + "HeaderCloudSync": "Sincroniza\u00e7\u00e3o na Nuvem", + "Downloads": "Downloads", + "HeaderMyDownloads": "Meus Downloads", + "HeaderOfflineDownloads": "M\u00eddia Offline", + "HeaderOfflineDownloadsDescription": "Download sua m\u00eddia para seus dispositivos para uso offline f\u00e1cil.", + "CloudSyncFeatureDescription": "Sincronize sua m\u00eddia para a nuvem para backup, arquivamento e convers\u00e3o f\u00e1ceis.", + "LiveTvFeatureDescription": "Assistir TV ao vivo em qualquer app Emby com um sintonizador de TV compat\u00edvel, instalado em seu servidor Emby.", + "DvrFeatureDescription": "Agendar grava\u00e7\u00f5es individuais de TV ao vivo, grava\u00e7\u00f5es de s\u00e9ries e mais com o Emby DVR.", + "CinemaModeFeatureDescription": "Modo Cinema oferece a voc\u00ea uma verdadeira experi\u00eancia de cinema com trailers e intros customizados antes da funcionalidade.", + "HeaderFreeApps": "Apps Emby gr\u00e1tis", + "FreeAppsFeatureDescription": "Aproveite acesso gr\u00e1tis a apps Emby para seus dispositivos.", + "HeaderBecomeProjectSupporter": "Obter Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Uma subscri\u00e7\u00e3o ativa do Emby Premiere \u00e9 requerida para criar a grava\u00e7\u00e3o automatizada de s\u00e9ries.", + "LabelEmailAddress": "Endere\u00e7o de E-mail:", + "PromoConvertRecordingsToStreamingFormat": "Converter automaticamente grava\u00e7\u00f5es para um formato amig\u00e1vel para streaming com Emby Premiere. Grava\u00e7\u00f5es ser\u00e3o convertidas em tempo real para MP4 ou MKV, baseado nas configura\u00e7\u00f5es do Servidor Emby.", + "FeatureRequiresEmbyPremiere": "Este recurso requer uma subscri\u00e7\u00e3o ativa do Emby Premiere", + "HeaderConvertYourRecordings": "Converter suas Grava\u00e7\u00f5es", + "Record": "Gravar", + "Save": "Salvar", + "Edit": "Editar", + "Download": "Download", + "Downloaded": "Transferido(s)", + "Downloading": "Transferindo", + "Advanced": "Avan\u00e7ado", + "Delete": "Excluir", + "HeaderDeleteItem": "Excluir item", + "ConfirmDeleteItem": "Excluir este item o excluir\u00e1 do sistema de arquivos e tamb\u00e9m da biblioteca de m\u00eddias. Deseja realmente continuar?", + "Refresh": "Atualizar", + "RefreshQueued": "Atualiza\u00e7\u00e3o iniciada.", + "AddToCollection": "Adicionar \u00e0 colet\u00e2nea", + "HeaderAddToCollection": "Adicionar \u00e0 Colet\u00e2nea", + "NewCollection": "Nova Colet\u00e2nea", + "LabelCollection": "Colet\u00e2nea:", + "Help": "Ajuda", + "LabelDisplayMode": "Mode de exibi\u00e7\u00e3o:", + "Desktop": "Desktop", + "Mobile": "Celular \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Selecione o tipo de tela para executar o Emby.", + "LabelDisplayLanguage": "Idioma para exibi\u00e7\u00e3o:", + "LabelDisplayLanguageHelp": "A tradu\u00e7\u00e3o do Emby \u00e9 um projeto em andamento.", + "LearnHowYouCanContribute": "Saiba como voc\u00ea pode contribuir.", + "NewCollectionHelp": "Colet\u00e2neas permitem que voc\u00ea crie grupos personalizados de filmes e outros conte\u00fados da biblioteca.", + "SearchForCollectionInternetMetadata": "Buscar artwork e metadados na internet", + "DisplayMissingEpisodesWithinSeasons": "Exibir epis\u00f3dios que faltam dentro das temporadas", + "DisplayMissingEpisodesWithinSeasonsHelp": "Isto tamb\u00e9m deve ser ativado para as bibliotecas de TV na configura\u00e7\u00e3o do Servidor Emby.", + "EnableThemeSongs": "Ativar m\u00fasicas-tema", + "EnableBackdrops": "Ativar imagens de fundo", + "EnableThemeSongsHelp": "Se ativadas, m\u00fasicas-tema ser\u00e3o reproduzidas em segundo plano ao navegar pela biblioteca.", + "EnableBackdropsHelp": "Se ativadas, imagens de fundo ser\u00e3o exibidas ao fundo de algumas p\u00e1ginas ao navegar pela biblioteca.", + "EnableThemeVideos": "Ativar m\u00fasicas-tema", + "EnableThemeVideosHelp": "Se ativadas, m\u00fasicas-tema ser\u00e3o reproduzidas em segundo plano ao navegar pela biblioteca.", + "RunAtStartup": "Executar ao iniciar", + "LabelScreensaver": "Protetor de Tela:", + "LabelSoundEffects": "Efeitos sonoros:", + "LabelSkin": "Skin:", + "LabelName": "Nome:", + "NewCollectionNameExample": "Exemplo: Colet\u00e2nea Star Wars", + "MessageItemsAdded": "Itens adicionados.", + "OptionNew": "Nova...", + "LabelPlaylist": "Lista de Reprodu\u00e7\u00e3o:", + "AddToPlaylist": "Adicionar \u00e0 lista de reprodu\u00e7\u00e3o", + "HeaderAddToPlaylist": "Adicionar \u00e0 Lista de Reprodu\u00e7\u00e3o", + "Subtitles": "Legendas", + "LabelTheme": "Tema:", + "LabelDashboardTheme": "Tema do painel do servidor:", + "SearchForSubtitles": "Buscar Legendas", + "LabelLanguage": "Idioma:", + "Search": "Busca", + "NoSubtitleSearchResultsFound": "Nenhum resultado encontrado.", + "File": "Arquivo", + "MessageAreYouSureDeleteSubtitles": "Deseja realmente excluir este arquivo de legendas?", + "ConfirmDeletion": "Confirmar Exclus\u00e3o", + "MySubtitles": "Minhas Legendas", + "MessageDownloadQueued": "Download enfileirado.", + "EditSubtitles": "Editar legendas", + "UnlockGuide": "Desbloquear Guia", + "RefreshMetadata": "Atualizar metadados", + "ReplaceExistingImages": "Substituir imagens existentes", + "ReplaceAllMetadata": "Substituir todos os metadados", + "SearchForMissingMetadata": "Buscar por metadados que faltam", + "LabelRefreshMode": "Mode de atualiza\u00e7\u00e3o:", + "NoItemsFound": "Nenhum item encontrado.", + "HeaderSaySomethingLike": "Diga Alguma Coisa Como...", + "ButtonTryAgain": "Tente Novamente", + "HeaderYouSaid": "Voc\u00ea Disse...", + "MessageWeDidntRecognizeCommand": "Desculpe, n\u00e3o reconhecemos este comando.", + "MessageIfYouBlockedVoice": "Se voc\u00ea negou o acesso de voz ao app, voc\u00ea necessitar\u00e1 reconfigurar antes de tentar novamente.", + "ValueDiscNumber": "Disco {0}", + "Unrated": "N\u00e3o-classificado", + "Favorite": "Favorito", + "Like": "Curti", + "Dislike": "N\u00e3o curti", + "RefreshDialogHelp": "Os metadados s\u00e3o atualizados com bases nas defini\u00e7\u00f5es e nos servi\u00e7os de internet que est\u00e3o ativos no painel do Servidor Emby.", + "Open": "Abrir", + "Play": "Reproduzir", + "AddToPlayQueue": "Adicionar \u00e0 fila de reprodu\u00e7\u00e3o", + "Shuffle": "Aleat\u00f3rio", + "Identify": "Identificar", + "EditImages": "Editar imagens", + "EditMetadata": "Editar metadados", + "Convert": "Converter", + "Sync": "Sincronizar", + "InstantMix": "Mix inst\u00e2ntaneo", + "ViewAlbum": "Ver \u00e1lbum", + "ViewArtist": "Ver artista", + "QueueAllFromHere": "Enfileirar todas a partir daqui", + "PlayAllFromHere": "Reproduzir todas a partir daqui", + "PlayFromBeginning": "Reproduzir do in\u00edcio", + "ResumeAt": "Retomar de {0}", + "RemoveFromPlaylist": "Remover da lista de reprodu\u00e7\u00e3o", + "RemoveFromCollection": "Remover da cole\u00e7\u00e3o", + "Sort": "Ordenar", + "Trailer": "Trailer", + "MarkPlayed": "Marcar como reproduzido", + "MarkUnplayed": "Marcar como n\u00e3o-reproduzido", + "GroupVersions": "Agrupar vers\u00f5es", + "PleaseSelectTwoItems": "Por favor selecione pelo menos dois itens.", + "TryMultiSelect": "Experimentar a Sele\u00e7\u00e3o M\u00faltipla", + "TryMultiSelectMessage": "Para editar itens m\u00faltiplos de m\u00eddia, basta clicar e segurar qualquer capa e selecionar os itens que gostaria de gerenciar. Experimente!", + "HeaderConfirmRecordingCancellation": "Confirmar Cancelamento da Grava\u00e7\u00e3o", + "MessageConfirmRecordingCancellation": "Cancelar grava\u00e7\u00e3o?", + "Error": "Erro", + "VoiceInput": "Entrada de voz", + "LabelContentType": "Tipo de conte\u00fado:", + "LabelPath": "Local:", + "Playlists": "Listas de Reprodu\u00e7\u00e3o", + "LabelTitle": "T\u00edtulo:", + "LabelOriginalTitle": "T\u00edtulo original:", + "LabelSortTitle": "T\u00edtulo para ordena\u00e7\u00e3o:", + "LabelDateAdded": "Data de adi\u00e7\u00e3o:", + "DateAdded": "Data da adi\u00e7\u00e3o", + "DatePlayed": "Data da reprodu\u00e7\u00e3o", + "ConfigureDateAdded": "Configure como a data de adi\u00e7\u00e3o \u00e9 determinada no painel do Servidor Emby nas defini\u00e7\u00f5es de Biblioteca", + "LabelStatus": "Status:", + "LabelArtists": "Artistas:", + "LabelArtistsHelp": "Separar m\u00faltiplos usando ;", + "HeaderAlbumArtists": "Artistas do \u00c1lbum", + "LabelAlbumArtists": "Artistas do \u00c1lbum:", + "LabelAlbum": "\u00c1lbum:", + "Artists": "Artistas", + "ImdbRating": "Avalia\u00e7\u00e3o IMDb", + "CommunityRating": "Avalia\u00e7\u00e3o da Comunidade", + "LabelCommunityRating": "Avalia\u00e7\u00e3o da comunidade:", + "LabelCriticRating": "Avalia\u00e7\u00e3o da cr\u00edtica:", + "CriticRating": "Avalia\u00e7\u00e3o da Cr\u00edtica", + "LabelWebsite": "Website:", + "LabelTagline": "Slogan:", + "LabelOverview": "Sinopse:", + "LabelShortOverview": "Sinopse curta:", + "LabelReleaseDate": "Data do lan\u00e7amento:", + "LabelYear": "Ano:", + "LabelPlaceOfBirth": "Local de nascimento:", + "Aired": "Exibido", + "LabelAirDays": "Dias da exibi\u00e7\u00e3o:", + "LabelAirTime": "Hor\u00e1rio:", + "LabelRuntimeMinutes": "Dura\u00e7\u00e3o (minutos):", + "LabelParentalRating": "Classifica\u00e7\u00e3o et\u00e1ria:", + "LabelCustomRating": "Classifica\u00e7\u00e3o personalizada:", + "LabelOriginalAspectRatio": "Propor\u00e7\u00e3o da imagem original:", + "Label3DFormat": "Formato 3D:", + "FormatValue": "Formato: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Combina\u00e7\u00e3o perfeita", + "EnableExternalVideoPlayers": "Ativar reprodutores de v\u00eddeo externos", + "EnableExternalVideoPlayersHelp": "Um menu do reprodutor externo ser\u00e1 exibido ao iniciar a reprodu\u00e7\u00e3o do v\u00eddeo.", + "HeaderSpecialEpisodeInfo": "Informa\u00e7\u00e3o do Epis\u00f3dio Especial", + "LabelAirsBeforeSeason": "Exibido antes da temporada:", + "LabelAirsAfterSeason": "Exibido depois da temporada:", + "LabelAirsBeforeEpisode": "Exibido antes do epis\u00f3dio:", + "HeaderExternalIds": "Ids Externos:", + "HeaderDisplaySettings": "Ajustes de Exibi\u00e7\u00e3o", + "LabelDisplayOrder": "Ordem de exibi\u00e7\u00e3o:", + "Display": "Exibir", + "Countries": "Pa\u00edses", + "Genres": "G\u00eaneros", + "Studios": "Est\u00fadios", + "Tags": "Tags", + "HeaderMetadataSettings": "Ajustes dos Metadados", + "People": "Pessoas", + "LabelMetadataDownloadLanguage": "Idioma preferido para download:", + "LabelLockItemToPreventChanges": "Bloquear este item para evitar altera\u00e7\u00f5es futuras", + "MessageLeaveEmptyToInherit": "Deixar em branco para herdar os ajustes de um item superior, ou o valor padr\u00e3o global", + "LabelCountry": "Pa\u00eds:", + "LabelDynamicExternalId": "Id de {0}:", + "LabelBirthYear": "Ano de nascimento:", + "LabelBirthDate": "Data de nascimento:", + "LabelDeathDate": "Data da morte:", + "LabelEndDate": "Data final:", + "LabelSeasonNumber": "N\u00famero da temporada:", + "LabelEpisodeNumber": "N\u00famero do epis\u00f3dio:", + "LabelTrackNumber": "N\u00famero da faixa:", + "LabelNumber": "N\u00famero:", + "LabelDiscNumber": "N\u00famero do disco:", + "LabelParentNumber": "N\u00famero do superior:", + "SortName": "Nome para ordena\u00e7\u00e3o", + "ReleaseDate": "Data de lan\u00e7amento", + "Continuing": "Em Exibi\u00e7\u00e3o", + "Ended": "Finalizada", + "HeaderEnabledFields": "Campos Ativados", + "HeaderEnabledFieldsHelp": "Desmarque um campo para bloque\u00e1-lo e evitar que seus dados sejam alterados.", + "Backdrops": "Imagens de Fundo", + "Images": "Imagens", + "Runtime": "Dura\u00e7\u00e3o", + "ProductionLocations": "Locais de produ\u00e7\u00e3o", + "BirthLocation": "Local de nascimento", + "ParentalRating": "Classifica\u00e7\u00e3o Et\u00e1ria", + "PlayCount": "N\u00famero de Reprodu\u00e7\u00f5es", + "Name": "Nome", + "Overview": "Sinopse", + "LabelType": "Tipo:", + "LabelPersonRole": "Personagem:", + "LabelPersonRoleHelp": "Exemplo: motorista do carrinho de sorvete", + "Actor": "Ator", + "Composer": "Compositor", + "Director": "Diretor", + "GuestStar": "Convidado Especial", + "Producer": "Produtor", + "Writer": "Escritor", + "MessageNoSyncJobsFound": "Nenhum download encontrado. Crie tarefas de download usando os bot\u00f5es Download encontrados no app.", + "MessageNoDownloadsFound": "Nenhum download offline. Baixe sua m\u00eddia para us\u00e1-la offline clicando em Download no app.", + "InstallingPackage": "Instalando {0}", + "PackageInstallCompleted": "Instala\u00e7\u00e3o de {0} conclu\u00edda.", + "PackageInstallFailed": "Instala\u00e7\u00e3o de {0} falhou.", + "PackageInstallCancelled": "Instala\u00e7\u00e3o de {0} cancelada.", + "SeriesYearToPresent": "{0} - Presente", + "ValueOneItem": "1 item", + "ValueOneSong": "1 m\u00fasica", + "ValueSongCount": "{0} m\u00fasicas", + "ValueOneMovie": "1 filme", + "ValueMovieCount": "{0} filmes", + "ValueOneSeries": "1 s\u00e9rie", + "ValueSeriesCount": "{0} s\u00e9ries", + "ValueOneEpisode": "1 epis\u00f3dio", + "ValueEpisodeCount": "{0} epis\u00f3dios", + "ValueOneGame": "1 jogo", + "ValueGameCount": "{0} jogos", + "ValueOneAlbum": "1 \u00e1lbum", + "ValueAlbumCount": "{0} \u00e1lbuns", + "ValueOneMusicVideo": "1 v\u00eddeo musical", + "ValueMusicVideoCount": "{0} v\u00eddeos musicais", + "ValueMinutes": "{0} min", + "Albums": "\u00c1lbuns", + "Songs": "M\u00fasicas", + "Books": "Livros", + "HeaderAudioBooks": "Livros de \u00c1udio", + "HeaderIdentifyItemHelp": "Digite um ou mais crit\u00e9rios de busca. Exclua o crit\u00e9rio para aumentar os resultados da busca.", + "PleaseEnterNameOrId": "Por favor, digite um nome ou Id externo.", + "MessageItemSaved": "Item salvo.", + "SearchResults": "Resultados da Busca", + "ServerNameIsRestarting": "Servidor Emby - {0} est\u00e1 reiniciando.", + "ServerNameIsShuttingDown": "Servidor Emby - {0} est\u00e1 desligando.", + "HeaderDeleteItems": "Excluir Itens", + "ConfirmDeleteItems": "Ao excluir estes itens voc\u00ea os excluir\u00e1 do sistema de arquivos e de sua biblioteca de m\u00eddias. Deseja realmente continuar?", + "PleaseRestartServerName": "Por favor reinicie o Servidor Emby - {0}.", + "LabelSyncJobName": "Nome da tarefa de sincroniza\u00e7\u00e3o:", + "SyncingDots": "Sincronizando...", + "ConvertingDots": "Convertendo...", + "LabelQuality": "Qualidade:", + "LabelSyncNoTargetsHelp": "Parece que voc\u00ea n\u00e3o possui nenhuma app que suporta o download offline.", + "DownloadingDots": "Transferindo...", + "HeaderSyncRequiresSub": "O Download requer uma subscri\u00e7\u00e3o ativa do Emby Premiere.", + "LearnMore": "Saiba mais", + "LabelProfile": "Perfil:", + "LabelBitrateMbps": "Taxa (Mbps):", + "ConvertUnwatchedVideosOnly": "Converter apenas v\u00eddeos n\u00e3o assistidos", + "SyncUnwatchedVideosOnly": "Transferir apenas v\u00eddeos n\u00e3o assistidos", + "ConvertUnwatchedVideosOnlyHelp": "Apenas v\u00eddeos n\u00e3o assistidos ser\u00e3o convertidos.", + "SyncUnwatchedVideosOnlyHelp": "Apenas v\u00eddeos n\u00e3o assistidos ser\u00e3o transferidos, e os v\u00eddeos ser\u00e3o removidos do dispositivo assim que forem assistidos.", + "AutomaticallySyncNewContent": "Transferir novo conte\u00fado automaticamente", + "AutomaticallySyncNewContentHelp": "Novo conte\u00fado adicionado a esta pasta ser\u00e1 automaticamente transferido para o dispositivo.", + "AutomaticallyConvertNewContent": "Converter novo conte\u00fado automaticamente", + "AutomaticallyConvertNewContentHelp": "Novo conte\u00fado adicionado a esta pasta ser\u00e1 automaticamente convertido.", + "LabelItemLimit": "Limite de itens:", + "ConvertItemLimitHelp": "Opcional. Definir um limite para o n\u00famero de itens que ser\u00e3o convertidos.", + "DownloadItemLimitHelp": "Opcional. Definir um limite para o n\u00famero de itens que ser\u00e3o baixados.", + "PleaseSelectDeviceToSyncTo": "Por favor, selecione um dispositivo para transferir.", + "Screenshots": "Screenshots", + "MoveRight": "Mover para direita", + "MoveLeft": "Mover para esquerda", + "ConfirmDeleteImage": "Apagar imagem?", + "HeaderEditImages": "Editar Imagens", + "Settings": "Ajustes", + "ShowIndicatorsFor": "Mostrar indicadores para:", + "NewEpisodes": "Novos epis\u00f3dios", + "Episodes": "Epis\u00f3dios", + "HDPrograms": "Programas em HD", + "Programs": "Programas", + "LiveBroadcasts": "Broadcasts ao vivo", + "Premieres": "Estr\u00e9ias", + "RepeatEpisodes": "Repetir epis\u00f3dios", + "DvrSubscriptionRequired": "Emby DVR requer uma assinatura ativa do Emby Premiere", + "HeaderCancelRecording": "Cancelar Grava\u00e7\u00e3o", + "CancelRecording": "Cancelar grava\u00e7\u00e3o", + "HeaderKeepRecording": "Continuar Gravando", + "HeaderCancelSeries": "Cancelar S\u00e9rie", + "HeaderKeepSeries": "Manter S\u00e9rie", + "HeaderLearnMore": "Saiba Mais", + "DeleteMedia": "Excluir m\u00eddia", + "SeriesSettings": "Configura\u00e7\u00f5es da s\u00e9rie", + "HeaderRecordingOptions": "Op\u00e7\u00f5es de Grava\u00e7\u00e3o", + "CancelSeries": "Cancelar s\u00e9rie", + "DoNotRecord": "N\u00e3o gravar", + "HeaderSeriesOptions": "Op\u00e7\u00f5es da S\u00e9rie", + "LabelChannels": "Canais:", + "ChannelNameOnly": "Somente canal {0}", + "Anytime": "A qualquer momento", + "AnyLanguage": "Qualquer idioma", + "AroundTime": "Em torno de {0}", + "All": "Tudo", + "AllChannels": "Todos os canais", + "LabelRecord": "Gravar:", + "NewEpisodesOnly": "Apenas novos epis\u00f3dios", + "AllEpisodes": "Todos os epis\u00f3dios", + "LabelStartWhenPossible": "Iniciar quando poss\u00edvel:", + "LabelStopWhenPossible": "Parar quando poss\u00edvel:", + "MinutesBefore": "minutos antes de", + "MinutesAfter": "minutos ap\u00f3s", + "SkipEpisodesAlreadyInMyLibrary": "N\u00e3o gravar epis\u00f3dios que j\u00e1 estejam em minha biblioteca", + "SkipEpisodesAlreadyInMyLibraryHelp": "Epis\u00f3dios ser\u00e3o comparados utilizando temporada e n\u00fameros de epis\u00f3dios, quando dispon\u00edveis.", + "LabelKeepUpTo": "Manter at\u00e9:", + "AsManyAsPossible": "Quantos forem poss\u00edveis", + "DefaultErrorMessage": "Ocorreu um erro ao processar o pedido. Por favor, tente novamente mais tarde.", + "LabelKeep:": "Manter:", + "UntilIDelete": "At\u00e9 eu excluir", + "UntilSpaceNeeded": "At\u00e9 o espa\u00e7o necess\u00e1rio", + "Categories": "Categorias", + "Sports": "Esportes", + "News": "Not\u00edcias", + "Movies": "Filmes", + "Kids": "Crian\u00e7as", + "EnableColorCodedBackgrounds": "Habilitar cores de fundo por c\u00f3digo", + "SortChannelsBy": "Ordenar canais por:", + "RecentlyWatched": "Assistido recentemente", + "ChannelNumber": "N\u00famero do canal", + "HeaderBenefitsEmbyPremiere": "Benef\u00edcios do Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "Por favor aproveite um minuto de reprodu\u00e7\u00e3o. Obrigado por testar Emby.", + "HeaderTryPlayback": "Testar Reprodu\u00e7\u00e3o", + "HowDidYouPay": "Como voc\u00ea pagou?", + "IHaveEmbyPremiere": "Eu tenho Emby Premiere", + "IPurchasedThisApp": "Eu comprei este app", + "ButtonRestorePreviousPurchase": "Recuperar Compra", + "ButtonUnlockWithPurchase": "Desbloquear com Compra", + "ButtonUnlockPrice": "Desbloquear {0}", + "EmbyPremiereMonthlyWithPrice": "Mensalidade Emby Premiere {0}", + "HeaderAlreadyPaid": "J\u00e1 Pagou?", + "ButtonPlayOneMinute": "Reproduzir Um Minuto", + "PlaceFavoriteChannelsAtBeginning": "Colocar canais favoritos no in\u00edcio", + "HeaderUnlockFeature": "Desbloquear Funcionalidade", + "MessageDidYouKnowCinemaMode": "Voc\u00ea sabia que com Emby Premiere, voc\u00ea pode melhorar sua experi\u00eancia com funcionalidades como o Modo Cinema?", + "MessageDidYouKnowCinemaMode2": "Modo Cinema lhe d\u00e1 uma verdadeira experi\u00eancia de cinema com trailers e introdu\u00e7\u00f5es customizadas antes da apresenta\u00e7\u00e3o principal.", + "HeaderPlayMyMedia": "Reproduzir minha M\u00eddia", + "HeaderDiscoverEmbyPremiere": "Descobrir o Emby Premiere", + "Items": "itens", + "OneChannel": "Um canal", + "ConfirmRemoveDownload": "Remover download?", + "RemoveDownload": "Remover download", + "KeepDownload": "Manter transfer\u00eancia", + "AddedOnValue": "Adicionado {0}", + "RemovingFromDevice": "Removendo do dispositivo", + "KeepOnDevice": "Manter no dispositivo", + "CancelDownload": "Cancelar download", + "SyncJobItemStatusReadyToTransfer": "Pronto para Transferir", + "SyncJobItemStatusSyncedMarkForRemoval": "Removendo do dispositivo", + "SyncJobItemStatusQueued": "Enfileirado", + "SyncJobItemStatusConverting": "Convertendo", + "SyncJobItemStatusTransferring": "Transferindo", + "SyncJobItemStatusSynced": "Baixado", + "SyncJobItemStatusFailed": "Falha", + "SyncJobItemStatusRemovedFromDevice": "Removido do dispositivo", + "SyncJobItemStatusCancelled": "Cancelado", + "Retry": "Tentar Novamente", + "HeaderMyDevice": "Meu Dispositivo", + "Continue": "Continuar", + "ContinueInSecondsValue": "Continuar em {0} segundos.", + "HeaderRemoteControl": "Controle Remoto", + "Disconnect": "Desconectar", + "EnableDisplayMirroring": "Ativar espelhamento de tela", + "HeaderPlayOn": "Reproduzir em", + "Quality": "Qualidade", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "Para restaurar sua compra anterior, por favor certifique-se que est\u00e1 com a sess\u00e3o aberta com a mesma conta Google (ou Amazon) que fez a compra originalmente. Certifique-se que a app store est\u00e1 ativada e que n\u00e3o est\u00e1 restringida por nenhum controle parental e tamb\u00e9m verifique que possui uma conex\u00e3o de internet ativa. Voc\u00ea s\u00f3 ter\u00e1 que fazer isto uma vez para restaurar sua compra anterior.", + "AspectRatio": "Propor\u00e7\u00e3o da imagem", + "Original": "Original", + "Fill": "Preencher", + "BestFit": "Mais prov\u00e1vel", + "MessageNoServersAvailableToConnect": "Nenhum servidor dispon\u00edvel para se conectar. Se foi convidado para compartilhar um servidor, aceite abaixo ou clicando no link no email.", + "MessagePlayAccessRestricted": "A reprodu\u00e7\u00e3o para este conte\u00fado est\u00e1 restrita. Por favor, contate o administrador do Servidor Emby para mais informa\u00e7\u00f5es.", + "Accept": "Aceitar", + "Reject": "Rejeitar", + "Connect": "Conectar", + "HeaderMyMedia": "Minha M\u00eddia", + "HeaderMyMediaSmall": "Minha M\u00eddia (pequeno)", + "LatestFromLibrary": "Mais Recentes {0}", + "ContinueWatching": "Continuar assistindo", + "HeaderLatestChannelMedia": "Itens de Canais Recentes", + "HeaderContinueWatching": "Continuar Assistindo", + "HeaderContinueListening": "Continuar Escutando", + "HeaderActiveRecordings": "Grava\u00e7\u00f5es Ativas", + "HeaderLatestRecordings": "Grava\u00e7\u00f5es Recentes", + "LabelSyncTo": "Sincronizar para:", + "LabelConvertTo": "Converter para:", + "Next": "Pr\u00f3ximo", + "LabelSource": "Fonte:", + "LabelVersion": "Vers\u00e3o:", + "AllLanguages": "Todos os idiomas", + "Previous": "Anterior", + "HeaderNextUp": "Pr\u00f3ximos", + "HeaderLatestFrom": "Mais recentes de {0}", + "LabelHomeScreenSectionValue": "Se\u00e7\u00e3o {0} da tela In\u00edcio:", + "SettingsSaved": "Configura\u00e7\u00f5es salvas.", + "None": "Nenhum(a)", + "More": "Mais", + "Up": "Para cima", + "Down": "Para baixo", + "Home": "In\u00edcio", + "Favorites": "Favoritos", + "HeaderHomeScreen": "Tela In\u00edcio", + "HeaderLatestChannelItems": "Itens de Canais Recentes", + "HeaderLibraryOrder": "Ordem da Biblioteca", + "HideWatchedContentFromLatestMedia": "Ocultar conte\u00fado assistido das m\u00eddias recentes", + "HeaderOnNow": "Em Exibi\u00e7\u00e3o", + "HeaderPlaybackError": "Erro na Reprodu\u00e7\u00e3o", + "PlaybackErrorNotAllowed": "Voc\u00ea n\u00e3o est\u00e1 autorizado a reproduzir este conte\u00fado. Por favor, contacte seu administrador do sistema para mais detalhes.", + "PlaybackErrorNoCompatibleStream": "N\u00e3o existem streams compat\u00edveis. Por favor, tente novamente mais tarde ou contate o administrador do sistema para mais detalhes.", + "PlaybackErrorPlaceHolder": "Por favor, insira o disco para reproduzir este v\u00eddeo.", + "Guide": "Guia", + "Suggestions": "Sugest\u00f5es", + "HeaderFavoriteCollections": "Colet\u00e2neas Favoritas", + "HeaderFavoritePlaylists": "Listas de Reprodu\u00e7\u00e3o Favoritas", + "Collections": "Colet\u00e2neas", + "LabelSelectFolderGroups": "Agrupar automaticamente o conte\u00fado das seguintes pastas dentro das visualiza\u00e7\u00f5es como Filmes, M\u00fasicas e TV:", + "LabelSelectFolderGroupsHelp": "Pastas que n\u00e3o est\u00e3o marcadas ser\u00e3o exibidas em sua pr\u00f3pria visualiza\u00e7\u00e3o.", + "Folders": "Pastas", + "DisplayInOtherHomeScreenSections": "Exibir nas se\u00e7\u00f5es da tela in\u00edcio como m\u00eddia recente e continuar assistindo", + "DisplayInMyMedia": "Exibir na tela in\u00edcio", + "Shows": "S\u00e9ries", + "HeaderLibraryFolders": "Pastas da Biblioteca", + "HeaderTermsOfPurchase": "Termos de Compra", + "PrivacyPolicy": "Pol\u00edtica de privacidade", + "TermsOfUse": "Termos de uso", + "RepeatMode": "Modo de repeti\u00e7\u00e3o", + "RepeatOne": "Repetir uma", + "RepeatAll": "Repetir todas", + "LabelDefaultScreen": "Tela padr\u00e3o:", + "ConfirmEndPlayerSession": "Deseja realmente desligar o Emby em {0}?", + "Yes": "Sim", + "No": "N\u00e3o", + "LiveTV": "TV ao Vivo", + "Schedule": "Agendar", + "Recordings": "Grava\u00e7\u00f5es", + "MarkWatched": "Marcar como assisitido", + "ScanForNewAndUpdatedFiles": "Rastrear por arquivos novos e atualizados", + "DirectStreamHelp1": "A m\u00eddia \u00e9 compat\u00edvel com o dispositivo, independente da resolu\u00e7\u00e3o e tipo de m\u00eddia (H.264, AC3, etc.), mas est\u00e1 em um contaminar incompat\u00edvel (.mkv, .avi, .wmv, etc.). O v\u00eddeo ser\u00e1 reempacotado em tempo real antes de transmitir para o dispositivo.", + "DirectStreamHelp2": "A Transmiss\u00e3o direta de um arquivo usa pouco processamento sem perda de qualidade do v\u00eddeo.", + "MediaIsBeingConverted": "A m\u00eddia est\u00e1 sendo convertida para um formato que \u00e9 compat\u00edvel com o dispositivo que reproduz a m\u00eddia.", + "StatsForNerds": "Estat\u00edsticas para nerds", + "LabelReasonForTranscoding": "Motivo da transcodifica\u00e7\u00e3o:", + "DirectPlaying": "Reprodu\u00e7\u00e3o direta", + "DirectStreaming": "Streaming direta", + "Transcoding": "Transcodifica\u00e7\u00e3o", + "ContainerBitrateExceedsLimit": "A taxa de bits da m\u00eddia excede o limite.", + "VideoCodecNotSupported": "Codec de v\u00eddeo n\u00e3o suportado", + "AudioCodecNotSupported": "Codec de \u00e1udio n\u00e3o suportado", + "SubtitleCodecNotSupported": "Formato da legenda n\u00e3o suportado", + "DirectPlayError": "Erro de reprodu\u00e7\u00e3o direta", + "ContainerNotSupported": "Container n\u00e3o suportado", + "VideoLevelNotSupported": "N\u00edvel do v\u00eddeo n\u00e3o suportado", + "AudioBitrateNotSupported": "Taxa de \u00e1udio n\u00e3o suportada", + "AudioChannelsNotSupported": "Canais de \u00e1udio n\u00e3o suportados", + "VideoResolutionNotSupported": "Resolu\u00e7\u00e3o de v\u00eddeo n\u00e3o suportada", + "AudioProfileNotSupported": "Perfil de \u00e1udio n\u00e3o suportado", + "AudioSampleRateNotSupported": "Taxa de sample de \u00e1udio n\u00e3o suportada", + "AnamorphicVideoNotSupported": "V\u00eddeo anam\u00f3rfico n\u00e3o suportado", + "InterlacedVideoNotSupported": "V\u00eddeo interla\u00e7ado n\u00e3o suportado", + "SecondaryAudioNotSupported": "Mudan\u00e7a de trilha de \u00e1udio n\u00e3o suportada", + "ErrorRemovingEmbyConnectAccount": "Ocorreu um erro ao remover a conta do Emby Connect. Por favor, verifique se possui conex\u00e3o com a internet e tente novamente.", + "HeaderEmbyAccountRemoved": "Conta do Emby Removida", + "MessageEmbyAccontRemoved": "A conta do Emby foi removida para este usu\u00e1rio", + "HeaderInvitationSent": "Convite Enviado", + "MessageInvitationSentToUser": "Um email foi enviado para {0}, convidando-os para aceitar seu convite.", + "MessageInvitationSentToNewUser": "Um email foi enviado para {0}, convidando-os a se registrarem no Emby.", + "GuestUserNotFound": "Usu\u00e1rio n\u00e3o encontrado. Por favor, verifique que o nome esteja correto e tente novamente, ou tente digitar o endere\u00e7o de email deles.", + "ErrorReachingEmbyConnect": "Ocorreu um erro ao acessar o servidor do Emby Connect. Por favor, verifique se possui uma conex\u00e3o com a internet e tente novamente.", + "ErrorAddingEmbyConnectAccount1": "Ocorreu um erro ao adicionar a conta do Emby Connect. Voc\u00ea criou uma conta do Emby? Registra-se em {0}.", + "ErrorAddingEmbyConnectAccount2": "Se ainda tiver problemas, por favor envie uma email para {0} a partir do endere\u00e7o de email usado na conta do Emby.", + "ErrorAddingGuestAccount1": "Ocorreu um erro ao adicionar a conta do Emby Connect. Os seus convidados criaram uma conta do Emby? Eles podem registrar-se em {0}.", + "ErrorAddingGuestAccount2": "Se ainda tiver problemas, por favor envie uma email para {0} e inclua seu endere\u00e7o de email, assim como os deles.", + "MessageEmbyAccountAdded": "A conta do Emby foi adicionada para este usu\u00e1rio.", + "MessagePendingEmbyAccountAdded": "A conta do Emby foi adicionada para este usu\u00e1rio. Um email ser\u00e1 enviado para o dono da conta. O convite precisar\u00e1 ser confirmado clicando no link dentro do email.", + "HeaderEmbyAccountAdded": "Conta do Emby Adicionada", + "LabelSubtitlePlaybackMode": "Modo de legendas:", + "ErrorDeletingItem": "Ocorreu um erro ao excluir o item do Servidor Emby. Por favor, verifique se o Servidor Emby possui acesso de grava\u00e7\u00e3o na pasta de m\u00eddia e tente novamente,", + "NoSubtitles": "Sem Legenda", + "Default": "Padr\u00e3o", + "Absolute": "Absoluto", + "Smart": "Inteligente", + "Small": "Pequena", + "Smaller": "Menor", + "Medium": "M\u00e9dia", + "Large": "Grande", + "ExtraLarge": "Extra grande", + "OnlyForcedSubtitles": "Apenas legendas for\u00e7adas", + "AlwaysPlaySubtitles": "Sempre reproduzir legendas", + "DefaultSubtitlesHelp": "Legendas s\u00e3o carregadas com base nas configura\u00e7\u00f5es padr\u00e3o e de legendas for\u00e7adas nos metadados embutidos. As prefer\u00eancias de idioma s\u00e3o consideradas quando existem m\u00faltiplas op\u00e7\u00f5es dispon\u00edveis.", + "SmartSubtitlesHelp": "As legendas que combinarem com a prefer\u00eancia do idioma ser\u00e3o carregadas quando o \u00e1udio estiver em um idioma estrangeiro.", + "HeaderSubtitleSettings": "Ajustes de Legenda", + "HeaderSubtitleAppearance": "Apar\u00eancia da Legenda", + "OnlyForcedSubtitlesHelp": "Apenas legendas marcadas como for\u00e7adas ser\u00e3o carregadas.", + "AlwaysPlaySubtitlesHelp": "As legendas que combinarem com a prefer\u00eancia de idioma ser\u00e3o carregadas independente do idioma do \u00e1udio.", + "NoSubtitlesHelp": "Legendas n\u00e3o ser\u00e3o carregadas por padr\u00e3o. Elas podem ser carregadas manualmente durante a reprodu\u00e7\u00e3o.", + "LabelPreferredSubtitleLanguage": "Idioma de legendas preferido:", + "LabelTextSize": "Tamanho do texto:", + "TheseSettingsAffectSubtitlesOnThisDevice": "Estes ajustes afetar\u00e3o as legendas neste dispositivo", + "LabelDropShadow": "Sombra:", + "LabelTextBackgroundColor": "Cor de fundo do texto:", + "LabelWindowBackgroundColor": "Cor de fundo do texto:", + "LabelFont": "Fonte:", + "LabelTextColor": "Cor do texto:", + "Raised": "Levantada", + "Depressed": "Deprimido", + "Uniform": "Uniforme", + "DropShadow": "Sombra", + "SmallCaps": "Mai\u00fasculas", + "SubtitleAppearanceSettingsDisclaimer": "Estes ajustes n\u00e3o ser\u00e3o aplicados \u00e0s legendas gr\u00e1ficas (PGS, DVD, etc) ou \u00e0s legendas que t\u00eam seus pr\u00f3prios estilos embutidos (ASS\/SSA).", + "LabelBurnSubtitles": "Gravar legendas:", + "OnlyImageFormats": "Apenas formatos de imagens (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determina se o servidor deveria gravar as legendas no v\u00eddeo ao convert\u00ea-lo, dependendo do formato da legenda. Evitar a grava\u00e7\u00e3o da legenda ir\u00e1 melhorar a performance do servidor. Selecione Auto para gravar a imagem baseado nos formatos (ex. VOBSUB, PGS, SUB\/IDX, etc.) assim como algumas legendas ASS\/SSA.", + "AllComplexFormats": "Todos os formatos complexos (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Estas configura\u00e7\u00f5es tamb\u00e9m se aplicam para qualquer reprodu\u00e7\u00e3o do Chromecast para este dispositivo.", + "HeaderWaitingForWifi": "Esperando por Wifi", + "WifiRequiredToDownload": "\u00c9 necess\u00e1ria uma conex\u00e3o Wifi para continuar a transferir.", + "HeaderDownloadSettings": "Configura\u00e7\u00f5es de Download", + "Hide": "Ocultar", + "HeaderStartNow": "Iniciar Agora", + "HeaderNextVideoPlayingInValue": "Pr\u00f3ximo V\u00eddeo Reproduzindo em {0}", + "HeaderNextEpisodePlayingInValue": "Novo Epis\u00f3dio Reproduzindo em {0}", + "HeaderSecondsValue": "{0} Segundos", + "AudioBitDepthNotSupported": "Profundidade de bit de \u00e1udio n\u00e3o suportada", + "VideoProfileNotSupported": "Perfil de v\u00eddeo n\u00e3o suportado", + "VideoFramerateNotSupported": "Taxa do v\u00eddeo n\u00e3o suportada", + "VideoBitDepthNotSupported": "Profundidade de bit de v\u00eddeo n\u00e3o suportada", + "RefFramesNotSupported": "N\u00famero de quadros de refer\u00eancia de v\u00eddeo n\u00e3o suportado", + "ErrorConnectServerUnreachable": "Ocorreu um erro ao executar a opera\u00e7\u00e3o solicitada. Seu servidor n\u00e3o pode contactar nosso Emby Connect Server em {0}. Por favor, verifique se seu servidor possui uma conex\u00e3o de internet ativa e se as comunica\u00e7\u00f5es est\u00e3o liberadas pelo firewall ou software de seguran\u00e7a instalados.", + "StopRecording": "Parar grava\u00e7\u00e3o", + "HeaderStopRecording": "Parar Grava\u00e7\u00e3o", + "ManageRecording": "Gerenciar grava\u00e7\u00e3o", + "LabelDropImageHere": "Soltar a imagem aqui, ou clicar para procurar.", + "MessageFileReadError": "Ocorreu um erro ao ler o arquivo. Por favor, tente novamente.", + "Browse": "Navegar", + "HeaderUploadImage": "Carregar Imagem", + "HeaderAddUpdateImage": "Adicionar\/Atualizar Imagem", + "LabelImageType": "Tipo de imagem:", + "Upload": "Carregar", + "Primary": "Capa", + "Art": "Arte", + "Backdrop": "Imagem de Fundo", + "Banner": "Banner", + "Box": "Caixa", + "BoxRear": "Caixa (traseira)", + "Disc": "Disco", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Imagem da tela", + "Thumb": "\u00cdcone", + "ValueSeconds": "{0} segundos", + "HeaderAudioSettings": "Ajustes de \u00c1udio", + "LabelAudioLanguagePreference": "\u00c1udio preferido para exibi\u00e7\u00e3o:", + "LabelPlayDefaultAudioTrack": "Reproduzir a faixa de \u00e1udio padr\u00e3o, independente do idioma", + "HeaderVideoQuality": "Qualidade do V\u00eddeo", + "CinemaModeConfigurationHelp": "O modo cinema traz a experi\u00eancia do cinema diretamente para a sua sala, possibilitando reproduzir trailers e introdu\u00e7\u00f5es personalizadas antes do filme principal.", + "EnableNextVideoInfoOverlay": "Ativar as informa\u00e7\u00f5es do pr\u00f3ximo v\u00eddeo durante a reprodu\u00e7\u00e3o", + "EnableNextVideoInfoOverlayHelp": "Ao final de um v\u00eddeo, exibe informa\u00e7\u00f5es sobre o pr\u00f3ximo v\u00eddeo que est\u00e1 na lista de reprodu\u00e7\u00e3o.", + "PlayNextEpisodeAutomatically": "Reproduzir pr\u00f3ximo epis\u00f3dio automaticamente", + "LabelMaxChromecastBitrate": "Qualidade para streaming do chromecast:", + "LabelSkipBackLength": "Tamanho do intervalo para retroceder", + "LabelSkipForwardLength": "Tamanho do intervalo para avan\u00e7ar", + "EnableCinemaMode": "Ativar modo cinema", + "LabelInternetQuality": "Qualidade da internet:", + "HeaderMusicQuality": "Qualidade da M\u00fasica:", + "LabelHomeNetworkQuality": "Qualidade da rede local:", + "HeaderLatestMedia": "M\u00eddias Recentes", + "HeaderRestartingEmbyServer": "Reiniciando o Servidor Emby", + "RestartPleaseWaitMessage": "Por favor, aguarde enquanto o Servidor Emby reinicia. Isto pode levar um ou dois minutos.", + "PlayNext": "Reproduzir pr\u00f3ximo", + "AllowSeasonalThemes": "Permitir temas sazonais autom\u00e1ticos", + "AllowSeasonalThemesHelp": "Se ativado, temas sazonais ir\u00e3o sobrepor a configura\u00e7\u00e3o de temas.", + "AutoBasedOnLanguageSetting": "Autom\u00e1tico (baseado na configura\u00e7\u00e3o do idioma)", + "LabelDateTimeLocale": "Hora local:", + "DirectorValue": "Diretor: {0}", + "DirectorsValue": "Diretores: {0}", + "GenreValue": "G\u00eanero: {0}", + "GenresValue": "G\u00eaneros: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "\u00c1udio:", + "LabelVideo": "V\u00eddeo:", + "LabelSubtitles": "Legendas:", + "Off": "Desligado", + "ShowTitle": "Exibir t\u00edtulo", + "ShowYear": "Exibir ano", + "Filters": "Filtros", + "Unplayed": "N\u00e3o Reproduzido", + "LabelTVHomeScreen": "Tela in\u00edcio do modo TV:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Agrupar por s\u00e9ries", + "HeaderVideoType": "Tipo de V\u00eddeo", + "HeaderSeriesStatus": "Status das S\u00e9ries", + "Features": "Recursos", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "M\u00fasicas Tema", + "ThemeVideos": "V\u00eddeos Tema", + "HeaderFavoriteMovies": "Filmes Favoritos", + "HeaderFavoriteShows": "S\u00e9ries Favoritas", + "HeaderFavoriteEpisodes": "Epis\u00f3dios Favoritos", + "HeaderFavoriteVideos": "V\u00eddeos Favoritos", + "HeaderFavoriteGames": "Jogos Favoritos", + "HeaderFavoriteArtists": "Artistas Favoritos", + "HeaderFavoriteAlbums": "\u00c1lbuns Favoritos", + "HeaderFavoriteSongs": "M\u00fasicas Favoritas", + "Ascending": "Ascendente", + "Descending": "Descendente", + "ColorPrimaries": "Cores prim\u00e1rias", + "ColorSpace": "Espa\u00e7o da cor", + "ColorTransfer": "Transfer\u00eancia da cor", + "VideoRange": "Faixa de v\u00eddeo", + "SeriesDisplayOrderHelp": "Ordenar epis\u00f3dios por data de exibi\u00e7\u00e3o, ordem de dvd ou n\u00fameros absolutos.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/pt-pt.json b/src/bower_components/emby-webcomponents/strings/pt-pt.json index e2db9bbfba..8aa5b73615 100644 --- a/src/bower_components/emby-webcomponents/strings/pt-pt.json +++ b/src/bower_components/emby-webcomponents/strings/pt-pt.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Ator", - "Add": "Adicionar", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Adicionar à lista de reprodução", - "AddedOnValue": "Added {0}", - "Advanced": "Avançado", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "Novo", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Imagens de Fundo", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Cancelar", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Reiniciar", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Compositor", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Excluir este item o excluirá do sistema de arquivos e também da biblioteca multimédia. Deseja realmente continuar?", - "ConfirmDeleteItems": "Ao excluir estes itens você os excluirá do sistema de arquivos e de sua biblioteca multimédia. Deseja realmente continuar?", - "ConfirmDeletion": "Confirmar Exclusão", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Conectar", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "A Continuar", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Dias", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Remover", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Diretor", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Editar", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Ativar modo cinema", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Terminado", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Erro", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "Este recurso requer uma subscrição ativa do Jellyfin Premiere", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Sexta", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Adicionar à Coleção", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Ajustes de Áudio", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirmar Cancelamento da Gravação", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Remover item", - "HeaderDeleteItems": "Remover Itens", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Campos Ativados", - "HeaderEnabledFieldsHelp": "Desmarque um campo para bloqueá-lo e evitar que seus dados sejam alterados.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Digite um ou mais critérios de busca. Exclua o critério para aumentar os resultados da busca.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Ajustes dos Metadados", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "Nova Gravação", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Erro na Reprodução", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Selecionar Data", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Informação do Episódio Especial", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Ajustes de Legenda", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Ajuda", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identificar", - "Images": "Imagens", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Mix instântaneo", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} itens", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "Formato 3D:", - "LabelAirDays": "Dias da exibição:", - "LabelAirTime": "Horário:", - "LabelAirsAfterSeason": "Exibido depois da temporada:", - "LabelAirsBeforeEpisode": "Exibido antes do episódio:", - "LabelAirsBeforeSeason": "Exibido antes da temporada:", - "LabelAlbum": "Álbum:", - "LabelAlbumArtists": "Artistas do Álbum:", - "LabelArtists": "Artistas:", - "LabelArtistsHelp": "Separa múltiplas com ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Avaliação da comunidade:", - "LabelContentType": "Tipo de conteúdo:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "País:", - "LabelCriticRating": "Avaliação da crítica:", - "LabelCustomRating": "Classificação personalizada:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Data adicionado:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Ordem de exibição:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "Data final:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Idioma:", - "LabelLockItemToPreventChanges": "Bloquear este item para evitar alterações futuras", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Idioma preferido para download:", - "LabelName": "Nome:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Proporção da imagem original:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Sinopse:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Classificação parental:", - "LabelPath": "Local:", - "LabelPersonRole": "Personagem:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Local de nascimento:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Data do lançamento:", - "LabelRuntimeMinutes": "Duração (minutos):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Sinopse curta:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Estado:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Slogan:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Tipo:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Saiba mais", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Uma subscrição Jellyfin Premiere é necessária para criar a gravação automática de séries.", - "MessageAreYouSureDeleteSubtitles": "Deseja realmente remover este arquivo de legendas?", - "MessageConfirmRecordingCancellation": "Deseja realmente cancelar esta gravação?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item salvo.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Deixar em branco para herdar os ajustes de um item superior, ou o valor padrão global", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Segunda", - "More": "Mais", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "Nova Coleção", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Exemplo: Coleção Guerra das Estrelas", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Abrir", - "OptionNew": "Nova...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Reproduzir", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Reproduzir próximo episódio automaticamente", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Por favor, digite um nome ou Id externo.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Por favor selecione pelo menos dois itens.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Produtor", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Gravar", - "RecordSeries": "Record series", - "RecordingCancelled": "Gravação cancelada.", - "RecordingScheduled": "Gravação agendada.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Atualizar", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repetir", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Substituir imagens existentes", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Sábado", - "Save": "Guardar", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Busca", - "SearchForCollectionInternetMetadata": "Procurar na internet por imagens e metadados", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Buscar Legendas", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "Este Servidor Jellyfin precisa ser atualizado. Para fazer download da versão mais recente, por favor visite {0}", - "Settings": "Ajustes", - "SettingsSaved": "Settings saved.", - "Share": "Partilhar", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Aleatório", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Domingo", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Quinta", - "TrackCount": "{0} faixas", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "Para editar múltiplos ficheiros de multimédia, basta clicar e segurar qualquer capa e selecionar os itens que gostaria de gerir. Experimente!", - "Tuesday": "Terça", - "Uniform": "Uniform", - "UnlockGuide": "Desbloquear Guia", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Especial - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Quarta", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Escritor", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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": "Especial - {0}", + "Share": "Partilhar", + "Add": "Adicionar", + "ServerUpdateNeeded": "Este Servidor Emby precisa ser atualizado. Para fazer download da vers\u00e3o mais recente, por favor visite {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "Novo", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repetir", + "TrackCount": "{0} faixas", + "ItemCount": "{0} itens", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Selecionar Data", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Cancelar", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Reiniciar", + "RecordingCancelled": "Grava\u00e7\u00e3o cancelada.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Grava\u00e7\u00e3o agendada.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "Nova Grava\u00e7\u00e3o", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Domingo", + "Monday": "Segunda", + "Tuesday": "Ter\u00e7a", + "Wednesday": "Quarta", + "Thursday": "Quinta", + "Friday": "Sexta", + "Saturday": "S\u00e1bado", + "Days": "Dias", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Uma subscri\u00e7\u00e3o Emby Premiere \u00e9 necess\u00e1ria para criar a grava\u00e7\u00e3o autom\u00e1tica 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.", + "FeatureRequiresEmbyPremiere": "Este recurso requer uma subscri\u00e7\u00e3o ativa do Emby Premiere", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Gravar", + "Save": "Guardar", + "Edit": "Editar", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Avan\u00e7ado", + "Delete": "Remover", + "HeaderDeleteItem": "Remover item", + "ConfirmDeleteItem": "Excluir este item o excluir\u00e1 do sistema de arquivos e tamb\u00e9m da biblioteca multim\u00e9dia. Deseja realmente continuar?", + "Refresh": "Atualizar", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Adicionar \u00e0 Cole\u00e7\u00e3o", + "NewCollection": "Nova Cole\u00e7\u00e3o", + "LabelCollection": "Collection:", + "Help": "Ajuda", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Procurar na internet por imagens e metadados", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Nome:", + "NewCollectionNameExample": "Exemplo: Cole\u00e7\u00e3o Guerra das Estrelas", + "MessageItemsAdded": "Items added.", + "OptionNew": "Nova...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Adicionar \u00e0 lista de reprodu\u00e7\u00e3o", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Buscar Legendas", + "LabelLanguage": "Idioma:", + "Search": "Busca", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Deseja realmente remover este arquivo de legendas?", + "ConfirmDeletion": "Confirmar Exclus\u00e3o", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Desbloquear Guia", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Substituir imagens existentes", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Abrir", + "Play": "Reproduzir", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Aleat\u00f3rio", + "Identify": "Identificar", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Mix inst\u00e2ntaneo", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Por favor selecione pelo menos dois itens.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "Para editar m\u00faltiplos ficheiros de multim\u00e9dia, basta clicar e segurar qualquer capa e selecionar os itens que gostaria de gerir. Experimente!", + "HeaderConfirmRecordingCancellation": "Confirmar Cancelamento da Grava\u00e7\u00e3o", + "MessageConfirmRecordingCancellation": "Deseja realmente cancelar esta grava\u00e7\u00e3o?", + "Error": "Erro", + "VoiceInput": "Voice Input", + "LabelContentType": "Tipo de conte\u00fado:", + "LabelPath": "Local:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Data adicionado:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Estado:", + "LabelArtists": "Artistas:", + "LabelArtistsHelp": "Separa m\u00faltiplas com ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Artistas do \u00c1lbum:", + "LabelAlbum": "\u00c1lbum:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Avalia\u00e7\u00e3o da comunidade:", + "LabelCriticRating": "Avalia\u00e7\u00e3o da cr\u00edtica:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Slogan:", + "LabelOverview": "Sinopse:", + "LabelShortOverview": "Sinopse curta:", + "LabelReleaseDate": "Data do lan\u00e7amento:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Local de nascimento:", + "Aired": "Aired", + "LabelAirDays": "Dias da exibi\u00e7\u00e3o:", + "LabelAirTime": "Hor\u00e1rio:", + "LabelRuntimeMinutes": "Dura\u00e7\u00e3o (minutos):", + "LabelParentalRating": "Classifica\u00e7\u00e3o parental:", + "LabelCustomRating": "Classifica\u00e7\u00e3o personalizada:", + "LabelOriginalAspectRatio": "Propor\u00e7\u00e3o da imagem original:", + "Label3DFormat": "Formato 3D:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Informa\u00e7\u00e3o do Epis\u00f3dio Especial", + "LabelAirsBeforeSeason": "Exibido antes da temporada:", + "LabelAirsAfterSeason": "Exibido depois da temporada:", + "LabelAirsBeforeEpisode": "Exibido antes do epis\u00f3dio:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Ordem de exibi\u00e7\u00e3o:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Ajustes dos Metadados", + "People": "People", + "LabelMetadataDownloadLanguage": "Idioma preferido para download:", + "LabelLockItemToPreventChanges": "Bloquear este item para evitar altera\u00e7\u00f5es futuras", + "MessageLeaveEmptyToInherit": "Deixar em branco para herdar os ajustes de um item superior, ou o valor padr\u00e3o global", + "LabelCountry": "Pa\u00eds:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "Data final:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "A Continuar", + "Ended": "Terminado", + "HeaderEnabledFields": "Campos Ativados", + "HeaderEnabledFieldsHelp": "Desmarque um campo para bloque\u00e1-lo e evitar que seus dados sejam alterados.", + "Backdrops": "Imagens de Fundo", + "Images": "Imagens", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Tipo:", + "LabelPersonRole": "Personagem:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Ator", + "Composer": "Compositor", + "Director": "Diretor", + "GuestStar": "Guest star", + "Producer": "Produtor", + "Writer": "Escritor", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Digite um ou mais crit\u00e9rios de busca. Exclua o crit\u00e9rio para aumentar os resultados da busca.", + "PleaseEnterNameOrId": "Por favor, digite um nome ou Id externo.", + "MessageItemSaved": "Item salvo.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Remover Itens", + "ConfirmDeleteItems": "Ao excluir estes itens voc\u00ea os excluir\u00e1 do sistema de arquivos e de sua biblioteca multim\u00e9dia. Deseja realmente continuar?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Saiba mais", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Ajustes", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Conectar", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "Mais", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Erro na Reprodu\u00e7\u00e3o", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Ajustes de Legenda", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Ajustes de \u00c1udio", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Reproduzir pr\u00f3ximo epis\u00f3dio automaticamente", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Ativar modo cinema", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/ro.json b/src/bower_components/emby-webcomponents/strings/ro.json index 21b12ec4e6..78ddc92edc 100644 --- a/src/bower_components/emby-webcomponents/strings/ro.json +++ b/src/bower_components/emby-webcomponents/strings/ro.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Anuleaza", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continua", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "S-a sfarsit", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Vineri", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Ajutor", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artisti:", - "LabelArtistsHelp": "Folosire separata multipla", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Tip continut:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Tara:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Limba:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Nume:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Luni", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Exemplu: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Sambata", - "Save": "Salveaza", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Căutare pe internet pentru postere și metadate", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Duminica", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Joi", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Marti", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Miercuri", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Anuleaza", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Duminica", + "Monday": "Luni", + "Tuesday": "Marti", + "Wednesday": "Miercuri", + "Thursday": "Joi", + "Friday": "Vineri", + "Saturday": "Sambata", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Salveaza", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Ajutor", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "C\u0103utare pe internet pentru postere \u0219i metadate", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Nume:", + "NewCollectionNameExample": "Exemplu: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Limba:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Tip continut:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artisti:", + "LabelArtistsHelp": "Folosire separata multipla", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Tara:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continua", + "Ended": "S-a sfarsit", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/ru.json b/src/bower_components/emby-webcomponents/strings/ru.json index 2dd6c9e803..dfa4876926 100644 --- a/src/bower_components/emby-webcomponents/strings/ru.json +++ b/src/bower_components/emby-webcomponents/strings/ru.json @@ -1,685 +1,689 @@ { - "Absolute": "Абсолютный", - "Accept": "Принять", - "AccessRestrictedTryAgainLater": "В настоящее время доступ запрещён. Повторите попытку позже.", - "Actor": "Актёр", - "Add": "Добавить", - "AddToCollection": "Добавить в коллекцию", - "AddToPlayQueue": "Добавить в очередь воспроизведения", - "AddToPlaylist": "Добавить в плей-лист", - "AddedOnValue": "Добавлено {0}", - "Advanced": "Расширенное", - "AirDate": "Дата эфира", - "Aired": "Эфирный", - "Albums": "Альбомы", - "All": "Все", - "AllChannels": "Все каналы", - "AllComplexFormats": "Все комлексные форматы (ASS, SSA, VOBSUB, PGS, SUB/IDX и т.д.)", - "AllEpisodes": "Все эпизоды", - "AllLanguages": "Все языки", - "AllowSeasonalThemes": "Разрешить автоматические сезонные темы", - "AllowSeasonalThemesHelp": "При включении, сезонные темы будут время от времени перекрывать вашу настройку темы.", - "AlwaysPlaySubtitles": "Всегда воспроизводить с субтитрами", - "AlwaysPlaySubtitlesHelp": "Субтитры, соответствующие настройке языка, будут загружаться независимо от языка аудио.", - "AnamorphicVideoNotSupported": "Анаморфное видео не поддерживается", - "AndroidUnlockRestoreHelp": "Чтобы восстановить предыдущую покупку, убедитесь, что вы вошли в устройство с той же самой учётной записью Google (или Amazon), с которой сделали покупку первоначально. Убедитесь, что магазин приложений включен и не ограничен каким-либо родительским контролем, а также убедитесь в наличии активного подключения к Интернету. Вы должны будете сделать это только один раз, чтобы восстановить предыдущую покупку.", - "AnyLanguage": "Любой язык", - "Anytime": "В любое время", - "AroundTime": "Около {0}", - "Art": "Виньетка", - "Artists": "Исполнители", - "AsManyAsPossible": "Как можно больше", - "Ascending": "По возрастанию", - "AspectRatio": "Соот-ие сторон", - "AttemptingWakeServer": "Идёт попытка разбудить ваш сервер. Ждите...", - "AttributeNew": "Новинка", - "AudioBitDepthNotSupported": "Разрядность аудио не поддерживается", - "AudioBitrateNotSupported": "Потоковая скорость аудио не поддерживается", - "AudioChannelsNotSupported": "Аудиоканалы не поддерживаются", - "AudioCodecNotSupported": "Аудиокодек не поддерживается", - "AudioProfileNotSupported": "Аудио профиль не поддерживается", - "AudioSampleRateNotSupported": "Частота дискретизации аудио не поддерживается", - "Auto": "Авто", - "AutoBasedOnLanguageSetting": "Авто (на основе настройки языка)", - "AutomaticallyConvertNewContent": "Автоматически преобразовать новое содержание", - "AutomaticallyConvertNewContentHelp": "Новое содержание, добавленное в данную папку, будет автоматически преобразовано.", - "AutomaticallySyncNewContent": "Автоматически загружать новое содержание", - "AutomaticallySyncNewContentHelp": "Новое содержание, добавленное в эту папку, авто-ки загружается на устр-во.", - "Backdrop": "Задник", - "Backdrops": "Задники", - "Banner": "Баннер", - "BestFit": "Автоподбор", - "BirthLocation": "Место рождения", - "Books": "Книги", - "Box": "Коробка", - "BoxRear": "Спинка коробки", - "Browse": "Навигация", - "BurnSubtitlesHelp": "Определяется, должен ли сервер внедрять субтитры при преобразовании видео в зависимости от формата субтитров. Избегание внедрения субтитров улучшит производительность сервера. Выберите «Авто» для записи основанных на графике форматов (например, VOBSUB, PGS, SUB/IDX и т.п.), а также некоторых субтитров ASS/SSA.", - "ButtonCancel": "Отменить", - "ButtonGotIt": "Понятно", - "ButtonOk": "Ок", - "ButtonPlayOneMinute": "Воспроизвести одну минуту", - "ButtonRestart": "Перезапустить", - "ButtonRestorePreviousPurchase": "Восстановить приобретение", - "ButtonTryAgain": "Повторить попытку", - "ButtonUnlockPrice": "Разблокировать {0}", - "ButtonUnlockWithPurchase": "Разблокировать посредством оплаты", - "CancelDownload": "Отменить загрузку", - "CancelRecording": "Отменить запись", - "CancelSeries": "Отменить сериал", - "Categories": "Категории", - "ChannelNameOnly": "Только канал {0}", - "ChannelNumber": "Номер канала", - "CinemaModeConfigurationHelp": "Режим кинозала предоставит вам впечатление настоящего зрительного зала с трейлерами и произвольными заставками перед фильмом.", - "CinemaModeFeatureDescription": "Режим кинозала предоставит вам впечатление настоящего зрительного зала с трейлерами и произвольными заставками перед фильмом.", - "CloudSyncFeatureDescription": "Синхронизация ваших медиаданных с облаком для удобства их резервного копирования, архивирования и преобразования.", - "Collections": "Коллекции", - "ColorPrimaries": "Основные цвета", - "ColorSpace": "Цветовое пространство", - "ColorTransfer": "Цветопередача", - "CommunityRating": "Общественная оценка", - "Composer": "Композитор", - "ConfigureDateAdded": "Как конфигурировать дату добавления определяется в Панели Jellyfin Server в параметрах Медиатеки", - "ConfirmDeleteImage": "Удалить рисунок?", - "ConfirmDeleteItem": "При удалении данного элемента, он удалится и из файловой системы, и из медиатеки. Вы действительно хотите продолжить?", - "ConfirmDeleteItems": "При удалении данных элементов, он удалится и из файловой системы, и из медиатеки. Вы действительно хотите продолжить?", - "ConfirmDeletion": "Подтверждение удаления", - "ConfirmEndPlayerSession": "Вы хотите завершить работу Jellyfin на {0}?", - "ConfirmRemoveDownload": "Изъять загрузку?", - "Connect": "Подсоединиться", - "ContainerBitrateExceedsLimit": "Потоковая скорость медиаданных превысила предел.", - "ContainerNotSupported": "Контейнер не поддерживается", - "Continue": "Продолжить", - "ContinueInSecondsValue": "Продолжение через {0} с.", - "ContinueWatching": "Продолжение просмотра", - "Continuing": "Продолжающееся", - "Convert": "Преобразовать", - "ConvertItemLimitHelp": "Необязательно. Установить предельное число элементов, которые будут преобразовываться.", - "ConvertUnwatchedVideosOnly": "Преобразовать только непросмотренные видео", - "ConvertUnwatchedVideosOnlyHelp": "Только непросмотренные видео будут преобразованы", - "ConvertingDots": "Преобразуется...", - "Countries": "Страны", - "CriticRating": "Оценка критиков", - "DateAdded": "Дата добавления", - "DatePlayed": "Дата воспроизведения", - "Days": "Дни", - "Default": "Умолчание", - "DefaultErrorMessage": "Произошла ошибка при обработке запроса. Повторите попытку позже.", - "DefaultSubtitlesHelp": "Загрузки субтитров определяются флагами \"По умолчанию\" и \"Форсированные\" во внедрённых метаданных. Языковые настройки учитываются при наличии нескольких опций.", - "Delete": "Удалить", - "DeleteMedia": "Удалить медиаданные", - "Depressed": "Вдавленная", - "Descending": "По убыванию", - "Desktop": "Рабочий стол", - "DirectPlayError": "Ошибка прямого воспроизведения", - "DirectPlaying": "Воспроизводится напрямую", - "DirectStreamHelp1": "Медиаданные совместимы с устройством в отношении разрешения и типа медиаданных (H.264, AC3, и т.д.), но в несовместимом файловом контейнере (.mkv, .avi, .wmv и т.д.). Видео будет повторно упаковано динамически перед его трансляцией на устройство.", - "DirectStreamHelp2": "При прямой трансляции файла расходуется очень мало вычислительной мощности без потери качества видео.", - "DirectStreaming": "Транслируется напрямую", - "Director": "Режиссёр", - "DirectorValue": "Режиссёр: {0}", - "DirectorsValue": "Режиссёры: {0}", - "Disc": "Диск", - "Disconnect": "Разъединиться", - "Dislike": "Не нравится", - "Display": "Отображение", - "DisplayInMyMedia": "Показывать на главном экране", - "DisplayInOtherHomeScreenSections": "Показывать в разделах главного экрана (нпр., новейшие медиаданные, продолжение просмотра и т.п.)", - "DisplayMissingEpisodesWithinSeasons": "Отображать отсутствующие эпизоды в пределах сезонов", - "DisplayMissingEpisodesWithinSeasonsHelp": "Это также должно быть включено для ТВ-медиатек при установке и настройке Jellyfin Server.", - "DisplayModeHelp": "Выберите тип экрана, где запущен Jellyfin.", - "DoNotRecord": "Не записывать", - "Down": "Вниз", - "Download": "Загрузить", - "DownloadItemLimitHelp": "Необязательно. Установить предельное число элементов, которые будут загружаться.", - "Downloaded": "Загруженное", - "Downloading": "Загружается", - "DownloadingDots": "Загружается...", - "Downloads": "Загрузки", - "DownloadsValue": "Загрузки: {0}", - "DropShadow": "Теневая", - "DvrFeatureDescription": "Включайте в расписание отдельные записи с эфира, записи сериалов и т.д. с помощью видеорекордера Jellyfin.", - "DvrSubscriptionRequired": "Для видеорекордера Jellyfin требуется действующая подписка Jellyfin Premiere.", - "Edit": "Правка", - "EditImages": "Править рисунки", - "EditMetadata": "Править метаданные", - "EditSubtitles": "Править субтитры", - "EnableBackdrops": "Включить задники", - "EnableBackdropsHelp": "При включении, задники будут отображаться фоном некоторых страниц при просмотре медиатеки.", - "EnableCinemaMode": "Включить режим кинозала", - "EnableColorCodedBackgrounds": "Включить цветовой фон", - "EnableDisplayMirroring": "Включить дублирование отображения", - "EnableExternalVideoPlayers": "Включить внешние проигрыватели видео", - "EnableExternalVideoPlayersHelp": "Меню внешнего проигрывателя будет показано при запуске воспроизведения видео.", - "EnableNextVideoInfoOverlay": "Включать во время воспроизведения сведения о последующем видео", - "EnableNextVideoInfoOverlayHelp": "В конце видео отображать информацию о последующем видео в текущем плей-листе.", - "EnableThemeSongs": "Включить тематические композиции", - "EnableThemeSongsHelp": "При включении, тематические композиции будут воспроизводиться фоном при просмотре медиатеки.", - "EnableThemeVideos": "Включить тематические видео", - "EnableThemeVideosHelp": "При включении, тематические видео будут воспроизводиться фоном при просмотре медиатеки.", - "Ended": "Прекращённое", - "EndsAtValue": "Конец в {0}", - "Episodes": "Эпизоды", - "Error": "Ошибка", - "ErrorAddingGuestAccount1": "Произошла ошибка при добавлении учётной записи Jellyfin Connect. Создал ли ваш гость учетную запись Jellyfin? Он сможет зарегистрироваться на {0}.", - "ErrorAddingGuestAccount2": "Если у вас всё ещё имеются вопросы, отправьте письмо на {0}, и приведите свой адрес Э-почты, наряду с их адресами.", - "ErrorAddingJellyfinConnectAccount1": "Произошла ошибка при добавлении учётной записи Jellyfin Connect. Создали ли вы учетную запись Jellyfin? Зарегистрируйтесь на {0}.", - "ErrorAddingJellyfinConnectAccount2": "Если у вас всё ещё имеются вопросы, отправьте письмо на {0} с адреса Э-почты, использованного в учетной записи Jellyfin.", - "ErrorConnectServerUnreachable": "Произошла ошибка при выполнении запрошенной операции. Ваш сервер не может связаться с нашим сервером Jellyfin Connect по адресу {0}. Убедитесь, что ваш сервер имеет активное интернет-соединение и что коммуникации разрешены в брандмауэре или ПО безопасности, которое у вас установлено.", - "ErrorDeletingItem": "Произошла ошибка при удалении элемента с Jellyfin Server. Проверьте, что у Jellyfin Server имеется доступ на запись в медиапапку и повторите попытку.", - "ErrorReachingJellyfinConnect": "Произошла ошибка при попытке достичь сервера Jellyfin Connect. Убедитесь, что у вас имеется действующее интернет-соединение и повторите попытку.", - "ErrorRemovingJellyfinConnectAccount": "Произошла ошибка при удалении учётной записи Jellyfin Connect. Убедитесь, что у вас имеется действующее интернет-соединение и повторите попытку.", - "ExtraLarge": "Очень крупный", - "Extras": "Допматериалы", - "Favorite": "Избранное", - "Favorites": "Избранное", - "FeatureRequiresJellyfinPremiere": "Для данной функции требуется действующая подписка Jellyfin Premiere.", - "Features": "Материалы", - "File": "Файл", - "Fill": "Заполнение", - "Filters": "Фильтры", - "Folders": "Папки", - "FormatValue": "Формат: {0}", - "FreeAppsFeatureDescription": "Воспользуйтесь бесплатным доступом к Jellyfin-приложениям для ваших устройств.", - "Friday": "пятница", - "GenreValue": "Жанр: {0}", - "Genres": "Жанры", - "GenresValue": "Жанры: {0}", - "GroupBySeries": "Группирование по сериалам", - "GroupVersions": "Сгруппировать версии", - "GuestStar": "Пригл. актёр", - "GuestUserNotFound": "Пользователь не найден. Убедитесь, что имя приведено верно и повторите попытку, или попробуйте ввести его адрес Э-почты.", - "Guide": "Телегид", - "HDPrograms": "HD-передачи", - "HeaderActiveRecordings": "Активные записи", - "HeaderAddToCollection": "Добавить в коллекцию", - "HeaderAddToPlaylist": "Добавление в плей-лист", - "HeaderAddUpdateImage": "Добавление/Обновление рисунка", - "HeaderAlbumArtists": "Исполнители альбома", - "HeaderAlreadyPaid": "Уже оплатили?", - "HeaderAppearsOn": "Фигурирует в", - "HeaderAudioBooks": "Аудиокниги", - "HeaderAudioSettings": "Параметры аудио", - "HeaderBecomeProjectSupporter": "Приобрести Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Компоненты Jellyfin Premiere", - "HeaderCancelRecording": "Отменить запись", - "HeaderCancelSeries": "Отмена сериала", - "HeaderCinemaMode": "Режим кинозала", - "HeaderCloudSync": "Облачная синхронизация", - "HeaderConfirmRecordingCancellation": "Подтверждение отмены записи", - "HeaderContinueListening": "Продолжение прослушивания", - "HeaderContinueWatching": "Продолжение просмотра", - "HeaderConvertYourRecordings": "Преобразование ваших записей", - "HeaderCustomizeHomeScreen": "Подстройка главного экрана", - "HeaderDeleteItem": "Удаление элемента", - "HeaderDeleteItems": "Удаление элементов", - "HeaderDisplaySettings": "Параметры отображения", - "HeaderDownloadSettings": "Параметры загрузки", - "HeaderEditImages": "Править рисунки", - "HeaderEnabledFields": "Включённые поля", - "HeaderEnabledFieldsHelp": "Снимите флажок, чтобы зафиксировать поле и защитить его данные от изменнений.", - "HeaderExternalIds": "Внешние идентификаторы:", - "HeaderFavoriteAlbums": "Избранные альбомы", - "HeaderFavoriteArtists": "Избранные исполнители", - "HeaderFavoriteCollections": "Избранные коллекции", - "HeaderFavoriteEpisodes": "Избранные эпизоды", - "HeaderFavoriteGames": "Избранные игры", - "HeaderFavoriteMovies": "Избранные фильмы", - "HeaderFavoritePlaylists": "Избранные плей-листы", - "HeaderFavoriteShows": "Избранные передачи", - "HeaderFavoriteSongs": "Избранные композиции", - "HeaderFavoriteVideos": "Избранные видео", - "HeaderFreeApps": "Бесплатные Jellyfin-приложения", - "HeaderHomeScreen": "Главный экран", - "HeaderIdentifyItemHelp": "Введите одно или несколько условий поиска. Изымите условие, чтобы прирастить найденные результаты.", - "HeaderInvitationSent": "Приглашение отправлено", - "HeaderJellyfinAccountAdded": "Учётная запись Jellyfin добавлена", - "HeaderJellyfinAccountRemoved": "Учётная запись Jellyfin изъята", - "HeaderKeepRecording": "Хранение записи", - "HeaderKeepSeries": "Хранение сериала", - "HeaderLatestChannelItems": "Новейшее из каналов", - "HeaderLatestChannelMedia": "Новейшее из каналов", - "HeaderLatestFrom": "Новейшее из {0}", - "HeaderLatestMedia": "Новейшие медиаданные", - "HeaderLatestRecordings": "Новейшие записи", - "HeaderLearnMore": "Подробнее...", - "HeaderLibraryFolders": "Медиатечные папки", - "HeaderLibraryOrder": "Порядок медиатек", - "HeaderMetadataSettings": "Параметры метаданных", - "HeaderMusicQuality": "Качество музыки", - "HeaderMyDevice": "Моё устройство", - "HeaderMyDownloads": "Мои загрузки", - "HeaderMyMedia": "Мои медиаданные", - "HeaderMyMediaSmall": "Мои медиаданные (компактно)", - "HeaderNewRecording": "Новая запись", - "HeaderNextEpisodePlayingInValue": "Следующий эпизод воспроизводится через {0}", - "HeaderNextUp": "Очередное", - "HeaderNextVideoPlayingInValue": "Следующее видео воспроизводится через {0}", - "HeaderOfflineDownloads": "Автономные медиаданные", - "HeaderOfflineDownloadsDescription": "Загрузить медиаданные на ваши устройства для удобного использования в автономном режиме.", - "HeaderOnNow": "В эфире", - "HeaderPhotoAlbums": "Фотоальбомы", - "HeaderPlayMyMedia": "Воспроизвести мои медиаданные", - "HeaderPlayOn": "Воспроизведение", - "HeaderPlaybackError": "Ошибка воспроизведения", - "HeaderRecordingOptions": "Опции записи", - "HeaderRemoteControl": "Удалённое управление", - "HeaderRestartingJellyfinServer": "Jellyfin Server перезапускается", - "HeaderSaySomethingLike": "Скажите что-то вроде...", - "HeaderSecondsValue": "{0} с", - "HeaderSelectDate": "Выбор даты", - "HeaderSeriesOptions": "Опции сериала", - "HeaderSeriesStatus": "Статус сериала", - "HeaderSpecialEpisodeInfo": "О спецэпизоде", - "HeaderStartNow": "Запустить немедленно", - "HeaderStopRecording": "Остановка записи", - "HeaderSubtitleAppearance": "Оформление субтитров", - "HeaderSubtitleSettings": "Параметры субтитров", - "HeaderSyncRequiresSub": "Для загрузки требуется действующая подписка Jellyfin Premiere.", - "HeaderTermsOfPurchase": "Условия приобреетения", - "HeaderTryPlayback": "Опробуйте воспроизведение", - "HeaderUnlockFeature": "Разблокировать компоненту", - "HeaderUploadImage": "Выкладка рисунка", - "HeaderVideoQuality": "Качество видео", - "HeaderVideoType": "Тип видео", - "HeaderWaitingForWifi": "В ожидании WiFi", - "HeaderWakeServer": "Пробуждение сервера", - "HeaderYouSaid": "Вы сказали...", - "Help": "Справка...", - "Hide": "Скрыть", - "HideWatchedContentFromLatestMedia": "Скрыть просмотренное содержание из Новейших медиаданных", - "Home": "Главное", - "Horizontal": "Горизонтально", - "HowDidYouPay": "Каким образом вы оплатили?", - "IHaveJellyfinPremiere": "У меня имеется Jellyfin Premiere", - "IPurchasedThisApp": "Я приобрёл данное приложение", - "Identify": "Распознать", - "Images": "Рисунки", - "ImdbRating": "Оценка IMDb", - "InstallingPackage": "Устанавливается {0}", - "InstantMix": "Автомикс...", - "InterlacedVideoNotSupported": "Чересстрочное видео не поддерживается", - "ItemCount": "{0} элемент(а/ов)", - "Items": "Элементы", - "KeepDownload": "Хранить загруженное", - "KeepOnDevice": "Хранить на устройстве", - "Kids": "Детям", - "Label3DFormat": "Формат 3D:", - "LabelAirDays": "Дни эфира:", - "LabelAirTime": "Время эфира:", - "LabelAirsAfterSeason": "Сезон airs_after:", - "LabelAirsBeforeEpisode": "Эпизод airs_before:", - "LabelAirsBeforeSeason": "Сезон airs_before:", - "LabelAlbum": "Альбом", - "LabelAlbumArtists": "Исполнители альбома:", - "LabelArtists": "Исполнители:", - "LabelArtistsHelp": "Для разделения используйте точку с запятой (;)", - "LabelAudio": "Аудио:", - "LabelAudioLanguagePreference": "Выбор языка аудио:", - "LabelBirthDate": "Дата рождения:", - "LabelBirthYear": "Год рождения:", - "LabelBitrateMbps": "Потоковая скорость, Мбит/с:", - "LabelBurnSubtitles": "Внедрение субтитров:", - "LabelChannels": "Каналы:", - "LabelCollection": "Коллекция:", - "LabelCommunityRating": "Общественная оценка:", - "LabelContentType": "Тип содержания:", - "LabelConvertTo": "Преобразовать в:", - "LabelCountry": "Страна:", - "LabelCriticRating": "Оценка критиков:", - "LabelCustomRating": "Произвольная возрастная категория:", - "LabelDashboardTheme": "Тема панели сервера:", - "LabelDateAdded": "Дата добавления:", - "LabelDateTimeLocale": "Дата и время:", - "LabelDeathDate": "Дата смерти:", - "LabelDefaultScreen": "Экран по умолчанию:", - "LabelDiscNumber": "Номер диска:", - "LabelDisplayLanguage": "Язык отображения:", - "LabelDisplayLanguageHelp": "Перевод Jellyfin ведётся на постоянной основе.", - "LabelDisplayMode": "Режим отображения:", - "LabelDisplayOrder": "Порядок отображения:", - "LabelDropImageHere": "Перетащите рисунок сюда или щёлкните для навигации", - "LabelDropShadow": "Окантовка:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "Адрес Э-почты:", - "LabelEndDate": "Конечная дата:", - "LabelEpisodeNumber": "Номер эпизода:", - "LabelFont": "Шрифт:", - "LabelHomeNetworkQuality": "Качество в домашней сети:", - "LabelHomeScreenSectionValue": "Главная страница - раздел {0}:", - "LabelImageType": "Тип рисунка:", - "LabelInternetQuality": "Качество в Интернете:", - "LabelItemLimit": "Лимит элементов:", - "LabelKeep:": "Хранить:", - "LabelKeepUpTo": "Хранить до:", - "LabelLanguage": "Язык:", - "LabelLockItemToPreventChanges": "Зафиксировать данный элемент, чтобы запретить будущие правки", - "LabelMaxChromecastBitrate": "Качество трансляции Chromecast:", - "LabelMetadataDownloadLanguage": "Выбор языка загружаемого:", - "LabelName": "Имя:", - "LabelNumber": "Номер:", - "LabelOriginalAspectRatio": "Исходное соот-ие сторон:", - "LabelOriginalTitle": "Оригинальное название:", - "LabelOverview": "Обзор:", - "LabelParentNumber": "Родительский номер:", - "LabelParentalRating": "Возрастная категория:", - "LabelPath": "Путь:", - "LabelPersonRole": "Роль:", - "LabelPersonRoleHelp": "Пример: Водитель фургона мороженщика", - "LabelPlaceOfBirth": "Место рождения:", - "LabelPlayDefaultAudioTrack": "Воспроизводить стандартную аудиодорожку независимо от языка", - "LabelPlaylist": "Плей-лист:", - "LabelPreferredSubtitleLanguage": "Выбор языка субтитров:", - "LabelProfile": "Профиль:", - "LabelQuality": "Качество:", - "LabelReasonForTranscoding": "Причина перекодирования:", - "LabelRecord": "Запись:", - "LabelRefreshMode": "Режим обновления:", - "LabelReleaseDate": "Дата выпуска:", - "LabelRuntimeMinutes": "Длительность, мин:", - "LabelScreensaver": "Хранитель экрана:", - "LabelSeasonNumber": "Номер сезона:", - "LabelSelectFolderGroups": "Автоматическое группирование внутрь аспектов (например: Кино, Музыка и ТВ) содержания из следующих папок:", - "LabelSelectFolderGroupsHelp": "Папки, при которых сняты флажки, будут отображаться самостоятельно в их собственных аспектах.", - "LabelShortOverview": "Краткий обзор:", - "LabelSkin": "Оболочка:", - "LabelSkipBackLength": "Время отмотки:", - "LabelSkipForwardLength": "Время промотки:", - "LabelSortBy": "Сортировка по:", - "LabelSortOrder": "Порядок сортировки:", - "LabelSortTitle": "Сортировка по названию:", - "LabelSoundEffects": "Звуковые эффекты:", - "LabelSource": "Источник:", - "LabelStartWhenPossible": "Начать, когда это возможно:", - "LabelStatus": "Статус:", - "LabelStopWhenPossible": "Остановить, когда это возможно:", - "LabelSubtitlePlaybackMode": "Режим субтитров:", - "LabelSubtitles": "Субтитры:", - "LabelSyncJobName": "Имя задания синхр-ии:", - "LabelSyncNoTargetsHelp": "Похоже, что настоящее время приложений, в которых поддерживается автономная загрузка, не имеется.", - "LabelSyncTo": "Синхронизация с:", - "LabelTVHomeScreen": "Главная страница при ТВ-режиме", - "LabelTagline": "Ключевая фраза:", - "LabelTextBackgroundColor": "Цвет фона текста:", - "LabelTextColor": "Цвет текста:", - "LabelTextSize": "Размер текста:", - "LabelTheme": "Тема:", - "LabelTitle": "Название:", - "LabelTrackNumber": "Номер дорожки:", - "LabelType": "Тип:", - "LabelVersion": "Версия:", - "LabelVideo": "Видео:", - "LabelWebsite": "Вебсайт:", - "LabelWindowBackgroundColor": "Цвет фона:", - "LabelYear": "Год:", - "Large": "Крупный", - "LatestFromLibrary": "Новейшее: {0}", - "LearnHowYouCanContribute": "Изучите, как вы можете внести свой вклад.", - "LearnMore": "Подробнее...", - "Like": "Нравится", - "LinksValue": "Ссылки: {0}", - "List": "Список", - "Live": "Трансляция", - "LiveBroadcasts": "Прямые трансляции", - "LiveTV": "Эфир", - "LiveTvFeatureDescription": "Транслируйте ТВ-эфир на любое Jellyfin-приложение с помощью совместимого тюнерного устройства, установленного на вашем Jellyfin Server.", - "LiveTvRequiresUnlock": "Эфирному ТВ требуется действующая подписка Jellyfin Premiere.", - "Logo": "Логотип", - "ManageRecording": "Управлять записью", - "MarkPlayed": "Отметить как воспр-ое", - "MarkUnplayed": "Отметить как невоспр-ое", - "MarkWatched": "Отметить как просмотренное", - "MediaIsBeingConverted": "Медиаданные преобразуются в формат, совместимый с устройством, которое воспроизводит эти медиаданные.", - "Medium": "Средний", - "Menu": "Меню", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Действующая подписка Jellyfin Premiere требуется для того, чтобы создавать автоматизированные серийные записи.", - "MessageAreYouSureDeleteSubtitles": "Вы действительно хотите удалить данный файл субитров?", - "MessageConfirmRecordingCancellation": "Отменить запись?", - "MessageDownloadQueued": "Загрузка в очереди.", - "MessageFileReadError": "Произошла ошибка при считывании файла. Повторите попытку позже.", - "MessageIfYouBlockedVoice": "Если отказано в голосовом доступе к приложению, перед новой попыткой вам необходимо переконфигурирование.", - "MessageInvitationSentToNewUser": "Письмо была отправлена к {0}, с предложением зарегистрироваться в Jellyfin.", - "MessageInvitationSentToUser": "Письмо было отправлено к {0}, с предложением принять ваше приглашение на совместный доступ.", - "MessageItemSaved": "Элемент сохранён.", - "MessageItemsAdded": "Элементы добавлены.", - "MessageJellyfinAccontRemoved": "Учётная запись Jellyfin была изъята у этого пользователя", - "MessageJellyfinAccountAdded": "Учётная запись Jellyfin была добавлена для этого пользователя", - "MessageLeaveEmptyToInherit": "Не заполняйте, чтобы наследовать параметры от родительского элемента, или глобальное значение по умолчанию.", - "MessageNoDownloadsFound": "Нет автономных загрузок. Загрузите медиаданные для автономного пользования, нажав «Загрузить» повсюду в приложении.", - "MessageNoServersAvailableToConnect": "Не имеется серверов для подсоединения. Если вы получили приглашение к совместному доступу к серверу, то подтвердите, что приняли его ниже, или щёлкнув по ссылке в э-почте.", - "MessageNoSyncJobsFound": "Загрузок не найдено. Создайте задание загрузки с помощью кнопок Загрузить, находящихся по всему приложению.", - "MessagePendingJellyfinAccountAdded": "Учётная запись Jellyfin была добавлена для этого пользователя. Письмо будет отправлено владельцу учётной записи. Приглашение нужно будет подтвердить, щёлкнув по ссылке в письме.", - "MessagePlayAccessRestricted": "Воспроизведение данного содержания в настоящее время ограничено. За дополнительными сведениями. обратитесь к вашему администратору Jellyfin Server.", - "MessageToValidateSupporter": "Если у вас имеется действующая подписка Jellyfin Premiere, убедитесь, что Jellyfin Premiere установлена и настроена в вашей Панели Jellyfin Server, которая доступна по щелчку по Jellyfin Premiere в главном меню.", - "MessageUnlockAppWithPurchaseOrSupporter": "Разблокируйте данный компонент посредством небольшой однократной оплаты, или с действующей подпиской Jellyfin Premiere .", - "MessageUnlockAppWithSupporter": "Разблокируйте данный компонент с действующей подпиской Jellyfin Premiere.", - "MessageWeDidntRecognizeCommand": "Данная команда не распознана.", - "MinutesAfter": "минут(у/ы) после", - "MinutesBefore": "минут(у/ы) до", - "Mobile": "Мобильный / Планшетный", - "Monday": "понедельник", - "More": "Ещё...", - "MoveLeft": "Двигать влево", - "MoveRight": "Двигать вправо", - "Movies": "Фильмы", - "MySubtitles": "Мои субтитры", - "Name": "Имя", - "NewCollection": "Новая коллекция", - "NewCollectionHelp": "Коллекции позволяют получить обособленные собрания фильмов и иного содержания медиатеки.", - "NewCollectionNameExample": "Пример: Звёздные войны (Коллекция)", - "NewEpisodes": "Новые эпизоды", - "NewEpisodesOnly": "Только новые эпизоды", - "News": "Новости", - "Next": "Следующее", - "No": "Нет", - "NoItemsFound": "Никаких элементов не найдено.", - "NoSubtitleSearchResultsFound": "Результатов не найдено.", - "NoSubtitles": "Без субтитров", - "NoSubtitlesHelp": "По умолчанию, субтитры не будут загружаться. Они могут быть все ещё включены вручную во время воспроизведения.", - "None": "Ничего", - "Normal": "Обычный", - "Off": "Выкл", - "OneChannel": "Один канал", - "OnlyForcedSubtitles": "Только форсированные субтитры", - "OnlyForcedSubtitlesHelp": "Загружены будут только форсированные субтитры.", - "OnlyImageFormats": "Только графические форматы (VOBSUB, PGS, SUB/IDX и т.д.)", - "Open": "Открыть", - "OptionNew": "Новое...", - "Original": "Исходное", - "OriginalAirDateValue": "Дата исходного эфира: {0}", - "Overview": "Обзор", - "PackageInstallCancelled": "Установка {0} отменена.", - "PackageInstallCompleted": "Установка {0} завершена.", - "PackageInstallFailed": "Установка {0} неудачна.", - "ParentalRating": "Возр. кат.", - "People": "Люди", - "PerfectMatch": "Полное соответствие", - "Photos": "Фотографии", - "PlaceFavoriteChannelsAtBeginning": "Разместить избранные каналы в начале", - "Play": "Воспр.", - "PlayAllFromHere": "Воспр. все отсюда", - "PlayCount": "Кол. воспроизведений", - "PlayFromBeginning": "Воспр. с начала", - "PlayNext": "Воспроизвести следующее", - "PlayNextEpisodeAutomatically": "Воспроизводить последующий эпизод автоматически", - "PlaybackErrorNoCompatibleStream": "В настоящее время совместимых потоков в наличии не имеется. Повторите попытку позже или за подробностями обратитесь к своему системному администратору.", - "PlaybackErrorNotAllowed": "В настоящее время вы не авторизованы чтобы воспроизводить данное содержание. За подробностями обратитесь к своему системному администратору.", - "PlaybackErrorPlaceHolder": "Вставьте диск, чтобы воспроизвести данное видео.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "Чтобы конфигурировать параметры воспроизведения по умолчанию, остановите воспроизведение видео, затем щелкните значок пользователя в правой верхней части приложения.", - "Played": "Воспроизведено", - "Playlists": "Плей-листы", - "PleaseEnterNameOrId": "Введите название или внешний ID.", - "PleaseRestartServerName": "Перезапустите Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Выберите устройство, куда загружать.", - "PleaseSelectTwoItems": "Выберите хотя бы два элемента.", - "Premiere": "Премьера", - "Premieres": "Премьеры", - "Previous": "Предыдущее", - "Primary": "Головной", - "PrivacyPolicy": "Политика конфиденциальности", - "Producer": "Продюсер", - "ProductionLocations": "Производ-ные площадки", - "Programs": "Передачи", - "PromoConvertRecordingsToStreamingFormat": "Автоматическое преобразование записей в удобный для трансляции формат с помощью Jellyfin Premiere. Записи будут динамически преобразовываться в MP4 или MKV, на основе параметров Jellyfin Server.", - "Quality": "Качество", - "QueueAllFromHere": "В очередь все отсюда", - "Raised": "Выпуклая", - "RecentlyWatched": "Недавно просмотренное", - "Record": "Записать", - "RecordSeries": "Записать сериал", - "RecordingCancelled": "Запись отменена.", - "RecordingScheduled": "Запись назначена.", - "Recordings": "Записи", - "RefFramesNotSupported": "Число опорных кадров видео не поддерживается", - "Refresh": "Обновить", - "RefreshDialogHelp": "Обновление метаданных определяются параметрами и интернет-услугами, которые включены в Панели Jellyfin Server.", - "RefreshMetadata": "Обновить метаданные", - "RefreshQueued": "Обновление в очереди.", - "Reject": "Отклонить", - "ReleaseDate": "Дата выпуска", - "RemoveDownload": "Изъять загрузку", - "RemoveFromCollection": "Изъять из коллекции", - "RemoveFromPlaylist": "Изъять из плей-листа", - "RemovingFromDevice": "Изымается из устройства", - "Repeat": "Повтор", - "RepeatAll": "Повторить все", - "RepeatEpisodes": "Повтор эпизодов", - "RepeatMode": "Режим повтора", - "RepeatOne": "Повторить раз", - "ReplaceAllMetadata": "Замена всех метаданных", - "ReplaceExistingImages": "Замена имеющихся рисунков", - "RestartPleaseWaitMessage": "Подождите, пока Jellyfin Server выключится и перезапустится. Это может занять минуту или две.", - "ResumeAt": "Возобновить с {0}", - "Retry": "Повторить", - "RunAtStartup": "Запускать при старте системы", - "Runtime": "Длительность", - "Saturday": "суббота", - "Save": "Сохранить", - "ScanForNewAndUpdatedFiles": "Сканирование новых и изменённых файлов", - "Schedule": "Расписание", - "Screenshot": "Снимок экрана", - "Screenshots": "Снимки экрана", - "Search": "Поиск", - "SearchForCollectionInternetMetadata": "Искать иллюстрации и метаданные в Интернете", - "SearchForMissingMetadata": "Поиск отсутствующих метаданных", - "SearchForSubtitles": "Поиск субтитров", - "SearchResults": "Результаты поиска", - "SecondaryAudioNotSupported": "Переключение аудио дорожек не поддерживается", - "SeriesCancelled": "Сериал отменён.", - "SeriesDisplayOrderHelp": "Упорядочивание эпизодов по дате эфира, порядку на DVD или абсолютной нумерации.", - "SeriesRecordingScheduled": "Запись сериала назначена.", - "SeriesSettings": "Параметры сериала", - "SeriesYearToPresent": "{0} - Н.В.", - "ServerNameIsRestarting": "Jellyfin Server - {0} перезапускается.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} завершает работу.", - "ServerUpdateNeeded": "Данный Jellyfin Server нуждается в обновлении. Чтобы загрузить свежую версию, посетите {0}", - "Settings": "Параметры", - "SettingsSaved": "Параметры сохранены.", - "Share": "Поделиться", - "ShowIndicatorsFor": "Показывать метки для:", - "ShowTitle": "Название передачи", - "ShowYear": "Год передачи", - "Shows": "Передачи", - "Shuffle": "Перемешать", - "SkipEpisodesAlreadyInMyLibrary": "Не записывать эпизоды, которые уже находятся в моей медиатеке", - "SkipEpisodesAlreadyInMyLibraryHelp": "Эпизоды будут сравниваться с помощью номеров сезонов и эпизодов, когда они имеются.", - "Small": "Мелкий", - "SmallCaps": "Малые прописные", - "Smaller": "Поменьше", - "Smart": "Умный", - "SmartSubtitlesHelp": "Субтитры, соответствующие настройке языка, будут загружаться, если аудио на иностранном языке.", - "Songs": "Композиции", - "Sort": "Сортировать", - "SortByValue": "Сортировка по {0}", - "SortChannelsBy": "Сортировать каналы по:", - "SortName": "Сорт. по названию", - "Sports": "Спорт", - "StatsForNerds": "Статистика для умников", - "StopRecording": "Остановить запись", - "Studios": "Студии", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Эти параметры также применимы к любому Chromecast-воспроизведению запущенному данным устройством.", - "SubtitleAppearanceSettingsDisclaimer": "Данные параметры не применимы к графическим субтитрам (PGS, DVD и т.д.) или к субтитрам, которые имеют внедрённые свои собственные стили (ASS/SSA).", - "SubtitleCodecNotSupported": "Формат субтитров не поддерживается", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "Чтобы конфигурировать внешний вид субтитров и языковые настройки, остановите воспроизведение видео, затем щелкните значок пользователя в правой верхней части приложения.", - "Subtitles": "Субтитры", - "Suggestions": "Предлагаемое", - "Sunday": "воскресенье", - "Sync": "Синхро", - "SyncJobItemStatusCancelled": "Отменено", - "SyncJobItemStatusConverting": "Преобразуется", - "SyncJobItemStatusFailed": "Неудачно", - "SyncJobItemStatusQueued": "В очереди", - "SyncJobItemStatusReadyToTransfer": "Готово к переносу", - "SyncJobItemStatusRemovedFromDevice": "Изъято из устройства", - "SyncJobItemStatusSynced": "Загружено", - "SyncJobItemStatusSyncedMarkForRemoval": "Изымается из устройства", - "SyncJobItemStatusTransferring": "Переносится", - "SyncUnwatchedVideosOnly": "Загрузить непросм-ые видео", - "SyncUnwatchedVideosOnlyHelp": "Загружаются только непросм-ые видео, а просм-ые изымаются с устр-ва.", - "SyncingDots": "Синхронизируется...", - "TV": "ТВ", - "Tags": "Теги", - "TagsValue": "Теги: {0}", - "TermsOfUse": "Условия использования", - "ThankYouForTryingEnjoyOneMinute": "Воспользуйтесь одной минутой воспроизведения. Благодарим вас за опробование Jellyfin.", - "ThemeSongs": "Тематические мелодии", - "ThemeVideos": "Тематические видео", - "TheseSettingsAffectSubtitlesOnThisDevice": "Эти параметры влияют на субтитры на данном устройстве", - "Thumb": "Бегунок", - "Thursday": "четверг", - "TrackCount": "{0} дорож(ки/ек)", - "Trailer": "Трейлер", - "Trailers": "Трейлеры", - "Transcoding": "Перекодируется", - "TryMultiSelect": "Попробуйте несвязное выделение", - "TryMultiSelectMessage": "Чтобы править несколько элементов медиаданных, просто щёлкните и удерживайте кнопку мыши на любом постере и выделите те элементы, которыми вы хотите управлять. Попробуйте это!", - "Tuesday": "вторник", - "Uniform": "Однородная", - "UnlockGuide": "Разблокировать телегид", - "Unplayed": "Невоспроизведённое", - "Unrated": "Без категории", - "UntilIDelete": "Пока я не удалю", - "UntilSpaceNeeded": "Пока не понадобится место", - "Up": "Вверх", - "Upload": "Выкладка", - "ValueAlbumCount": "{0} альбом(а/ов)", - "ValueDiscNumber": "Диск {0}", - "ValueEpisodeCount": "{0} эпизод(а/ов)", - "ValueGameCount": "{0} игр(ы)", - "ValueMinutes": "{0} мин", - "ValueMovieCount": "{0} фильм(а/ов)", - "ValueMusicVideoCount": "{0} музыкальных видео", - "ValueOneAlbum": "1 альбом", - "ValueOneEpisode": "1 эпизод", - "ValueOneGame": "1 игра", - "ValueOneItem": "1 элемент", - "ValueOneMovie": "1 фильм", - "ValueOneMusicVideo": "1 музыкальное видео", - "ValueOneSeries": "1 сериал", - "ValueOneSong": "1 композиция", - "ValueSeconds": "{0} сек", - "ValueSeriesCount": "{0} сериал(а/ов)", - "ValueSongCount": "{0} композици(и/й)", - "ValueSpecialEpisodeName": "Спецэпизод - {0}", - "Vertical": "Вертикально", - "VideoBitDepthNotSupported": "Глубина цвета видео не поддерживается", - "VideoCodecNotSupported": "Видеокодек не поддерживается", - "VideoFramerateNotSupported": "Частота кадров видео не поддерживается", - "VideoLevelNotSupported": "Уровень видео не поддерживается", - "VideoProfileNotSupported": "Видео профиль не поддерживается", - "VideoRange": "Диапазон видео", - "VideoResolutionNotSupported": "Разрешение видео не поддерживается", - "ViewAlbum": "Посмотреть альбом", - "ViewArtist": "Посмотреть исполнителя", - "VoiceInput": "Голосовой ввод", - "WakeServer": "Разбудить сервер", - "WakeServerError": "Пакеты Wake On LAN были отправлены на вашу серверную машину, однако, мы не смогли соединиться с Jellyfin Server. Возможно, вашей машине потребуется немного больше времени для пробуждения, или Jellyfin Server не может активно работать на данной машине.", - "WakeServerSuccess": "Успешно!", - "Watched": "Просмотрено", - "Wednesday": "среда", - "WifiRequiredToDownload": "WiFi-соединение требуется для продолжения загрузки.", - "Writer": "Сценарист", - "Yes": "Да" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "\u0420\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0439\u0442\u0435 \u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u043e\u0439 \u043e\u043f\u043b\u0430\u0442\u044b, \u0438\u043b\u0438 \u0441 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u043e\u0439 Emby Premiere .", + "MessageUnlockAppWithSupporter": "\u0420\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0439\u0442\u0435 \u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u043e\u0439 Emby Premiere.", + "MessageToValidateSupporter": "\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 Emby Premiere, \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e Emby Premiere \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0432 \u0432\u0430\u0448\u0435\u0439 \u041f\u0430\u043d\u0435\u043b\u0438 Emby Server, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u043f\u043e \u0449\u0435\u043b\u0447\u043a\u0443 \u043f\u043e Emby Premiere \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u043c\u0435\u043d\u044e.", + "ValueSpecialEpisodeName": "\u0421\u043f\u0435\u0446\u044d\u043f\u0438\u0437\u043e\u0434 - {0}", + "Share": "\u041f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f", + "Add": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c", + "ServerUpdateNeeded": "\u0414\u0430\u043d\u043d\u044b\u0439 Emby Server \u043d\u0443\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438. \u0427\u0442\u043e\u0431\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0441\u0432\u0435\u0436\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e, \u043f\u043e\u0441\u0435\u0442\u0438\u0442\u0435 {0}", + "LiveTvRequiresUnlock": "\u042d\u0444\u0438\u0440\u043d\u043e\u043c\u0443 \u0422\u0412 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 Emby Premiere.", + "AttributeNew": "\u041d\u043e\u0432\u0438\u043d\u043a\u0430", + "Premiere": "\u041f\u0440\u0435\u043c\u044c\u0435\u0440\u0430", + "Live": "\u0422\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u044f", + "Repeat": "\u041f\u043e\u0432\u0442\u043e\u0440", + "TrackCount": "{0} \u0434\u043e\u0440\u043e\u0436(\u043a\u0438\/\u0435\u043a)", + "ItemCount": "{0} \u044d\u043b\u0435\u043c\u0435\u043d\u0442(\u0430\/\u043e\u0432)", + "OriginalAirDateValue": "\u0414\u0430\u0442\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u044d\u0444\u0438\u0440\u0430: {0}", + "EndsAtValue": "\u041a\u043e\u043d\u0435\u0446 \u0432 {0}", + "HeaderSelectDate": "\u0412\u044b\u0431\u043e\u0440 \u0434\u0430\u0442\u044b", + "Watched": "\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043e", + "AirDate": "\u0414\u0430\u0442\u0430 \u044d\u0444\u0438\u0440\u0430", + "Played": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u043e", + "ButtonOk": "\u041e\u043a", + "ButtonCancel": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c", + "AccessRestrictedTryAgainLater": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u0437\u0430\u043f\u0440\u0435\u0449\u0451\u043d. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.", + "ButtonGotIt": "\u041f\u043e\u043d\u044f\u0442\u043d\u043e", + "ButtonRestart": "\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c", + "RecordingCancelled": "\u0417\u0430\u043f\u0438\u0441\u044c \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430.", + "SeriesCancelled": "\u0421\u0435\u0440\u0438\u0430\u043b \u043e\u0442\u043c\u0435\u043d\u0451\u043d.", + "RecordingScheduled": "\u0417\u0430\u043f\u0438\u0441\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430.", + "SeriesRecordingScheduled": "\u0417\u0430\u043f\u0438\u0441\u044c \u0441\u0435\u0440\u0438\u0430\u043b\u0430 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430.", + "HeaderNewRecording": "\u041d\u043e\u0432\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c", + "WakeServer": "\u0420\u0430\u0437\u0431\u0443\u0434\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440", + "HeaderWakeServer": "\u041f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430", + "AttemptingWakeServer": "\u0418\u0434\u0451\u0442 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u0442\u044c \u0432\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440. \u0416\u0434\u0438\u0442\u0435...", + "WakeServerSuccess": "\u0423\u0441\u043f\u0435\u0448\u043d\u043e!", + "HeaderCustomizeHomeScreen": "\u041f\u043e\u0434\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430", + "WakeServerError": "\u041f\u0430\u043a\u0435\u0442\u044b Wake On LAN \u0431\u044b\u043b\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0430 \u0432\u0430\u0448\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443, \u043e\u0434\u043d\u0430\u043a\u043e, \u043c\u044b \u043d\u0435 \u0441\u043c\u043e\u0433\u043b\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c\u0441\u044f \u0441 Emby Server. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0432\u0430\u0448\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u044f, \u0438\u043b\u0438 Emby Server \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435.", + "Sunday": "\u0432\u043e\u0441\u043a\u0440\u0435\u0441\u0435\u043d\u044c\u0435", + "Monday": "\u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a", + "Tuesday": "\u0432\u0442\u043e\u0440\u043d\u0438\u043a", + "Wednesday": "\u0441\u0440\u0435\u0434\u0430", + "Thursday": "\u0447\u0435\u0442\u0432\u0435\u0440\u0433", + "Friday": "\u043f\u044f\u0442\u043d\u0438\u0446\u0430", + "Saturday": "\u0441\u0443\u0431\u0431\u043e\u0442\u0430", + "Days": "\u0414\u043d\u0438", + "SortByValue": "\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u043e {0}", + "LabelSortBy": "\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u043e:", + "LabelSortOrder": "\u041f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438:", + "HeaderPhotoAlbums": "\u0424\u043e\u0442\u043e\u0430\u043b\u044c\u0431\u043e\u043c\u044b", + "Photos": "\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438", + "HeaderAppearsOn": "\u0424\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u0442 \u0432", + "List": "\u0421\u043f\u0438\u0441\u043e\u043a", + "RecordSeries": "\u0417\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b", + "HeaderCinemaMode": "\u0420\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0437\u0430\u043b\u0430", + "HeaderCloudSync": "\u041e\u0431\u043b\u0430\u0447\u043d\u0430\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f", + "Downloads": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0438", + "HeaderMyDownloads": "\u041c\u043e\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438", + "HeaderOfflineDownloads": "\u0410\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u044b\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435", + "HeaderOfflineDownloadsDescription": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0432\u0430\u0448\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435.", + "CloudSyncFeatureDescription": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u0430\u0448\u0438\u0445 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043e\u0431\u043b\u0430\u043a\u043e\u043c \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0438\u0445 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0433\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0430\u0440\u0445\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f.", + "LiveTvFeatureDescription": "\u0422\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u0443\u0439\u0442\u0435 \u0422\u0412-\u044d\u0444\u0438\u0440 \u043d\u0430 \u043b\u044e\u0431\u043e\u0435 Emby-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0433\u043e \u0442\u044e\u043d\u0435\u0440\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043d\u0430 \u0432\u0430\u0448\u0435\u043c Emby Server.", + "DvrFeatureDescription": "\u0412\u043a\u043b\u044e\u0447\u0430\u0439\u0442\u0435 \u0432 \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0441 \u044d\u0444\u0438\u0440\u0430, \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u0438 \u0442.\u0434. \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u0438\u0434\u0435\u043e\u0440\u0435\u043a\u043e\u0440\u0434\u0435\u0440\u0430 Emby.", + "CinemaModeFeatureDescription": "\u0420\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0437\u0430\u043b\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0432\u0430\u043c \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0433\u043e \u0437\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043b\u0430 \u0441 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u0430\u043c\u0438 \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0430\u043c\u0438 \u043f\u0435\u0440\u0435\u0434 \u0444\u0438\u043b\u044c\u043c\u043e\u043c.", + "HeaderFreeApps": "\u0411\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0435 Emby-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f", + "FreeAppsFeatureDescription": "\u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a Emby-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c \u0434\u043b\u044f \u0432\u0430\u0448\u0438\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432.", + "HeaderBecomeProjectSupporter": "\u041f\u0440\u0438\u043e\u0431\u0440\u0435\u0441\u0442\u0438 Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "\u0414\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 Emby Premiere \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0435\u0440\u0438\u0439\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438.", + "LabelEmailAddress": "\u0410\u0434\u0440\u0435\u0441 \u042d-\u043f\u043e\u0447\u0442\u044b:", + "PromoConvertRecordingsToStreamingFormat": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0432 \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Emby Premiere. \u0417\u0430\u043f\u0438\u0441\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 MP4 \u0438\u043b\u0438 MKV, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 Emby Server.", + "FeatureRequiresEmbyPremiere": "\u0414\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 Emby Premiere.", + "HeaderConvertYourRecordings": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0430\u0448\u0438\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439", + "Record": "\u0417\u0430\u043f\u0438\u0441\u0430\u0442\u044c", + "Save": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c", + "Edit": "\u041f\u0440\u0430\u0432\u043a\u0430", + "Download": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c", + "Downloaded": "\u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u043e\u0435", + "Downloading": "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f", + "Advanced": "\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u043e\u0435", + "Delete": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c", + "HeaderDeleteItem": "\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430", + "ConfirmDeleteItem": "\u041f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430, \u043e\u043d \u0443\u0434\u0430\u043b\u0438\u0442\u0441\u044f \u0438 \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0438 \u0438\u0437 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438. \u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?", + "Refresh": "\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c", + "RefreshQueued": "\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438.", + "AddToCollection": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e", + "HeaderAddToCollection": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e", + "NewCollection": "\u041d\u043e\u0432\u0430\u044f \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f", + "LabelCollection": "\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f:", + "Help": "\u0421\u043f\u0440\u0430\u0432\u043a\u0430...", + "LabelDisplayMode": "\u0420\u0435\u0436\u0438\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f:", + "Desktop": "\u0420\u0430\u0431\u043e\u0447\u0438\u0439 \u0441\u0442\u043e\u043b", + "Mobile": "\u041c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0439 \/ \u041f\u043b\u0430\u043d\u0448\u0435\u0442\u043d\u044b\u0439", + "TV": "\u0422\u0412", + "DisplayModeHelp": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0438\u043f \u044d\u043a\u0440\u0430\u043d\u0430, \u0433\u0434\u0435 \u0437\u0430\u043f\u0443\u0449\u0435\u043d Emby.", + "LabelDisplayLanguage": "\u042f\u0437\u044b\u043a \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f:", + "LabelDisplayLanguageHelp": "\u041f\u0435\u0440\u0435\u0432\u043e\u0434 Emby \u0432\u0435\u0434\u0451\u0442\u0441\u044f \u043d\u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0439 \u043e\u0441\u043d\u043e\u0432\u0435.", + "LearnHowYouCanContribute": "\u0418\u0437\u0443\u0447\u0438\u0442\u0435, \u043a\u0430\u043a \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u043d\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0439 \u0432\u043a\u043b\u0430\u0434.", + "NewCollectionHelp": "\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0431\u043e\u0441\u043e\u0431\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u043e\u0431\u0440\u0430\u043d\u0438\u044f \u0444\u0438\u043b\u044c\u043c\u043e\u0432 \u0438 \u0438\u043d\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438.", + "SearchForCollectionInternetMetadata": "\u0418\u0441\u043a\u0430\u0442\u044c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435", + "DisplayMissingEpisodesWithinSeasons": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u0441\u0435\u0437\u043e\u043d\u043e\u0432", + "DisplayMissingEpisodesWithinSeasonsHelp": "\u042d\u0442\u043e \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u043e \u0434\u043b\u044f \u0422\u0412-\u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a \u043f\u0440\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 Emby Server.", + "EnableThemeSongs": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438", + "EnableBackdrops": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0437\u0430\u0434\u043d\u0438\u043a\u0438", + "EnableThemeSongsHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0444\u043e\u043d\u043e\u043c \u043f\u0440\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438.", + "EnableBackdropsHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0437\u0430\u0434\u043d\u0438\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0444\u043e\u043d\u043e\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u043f\u0440\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438.", + "EnableThemeVideos": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0432\u0438\u0434\u0435\u043e", + "EnableThemeVideosHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0432\u0438\u0434\u0435\u043e \u0431\u0443\u0434\u0443\u0442 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0444\u043e\u043d\u043e\u043c \u043f\u0440\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438.", + "RunAtStartup": "\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b", + "LabelScreensaver": "\u0425\u0440\u0430\u043d\u0438\u0442\u0435\u043b\u044c \u044d\u043a\u0440\u0430\u043d\u0430:", + "LabelSoundEffects": "\u0417\u0432\u0443\u043a\u043e\u0432\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b:", + "LabelSkin": "\u041e\u0431\u043e\u043b\u043e\u0447\u043a\u0430:", + "LabelName": "\u0418\u043c\u044f:", + "NewCollectionNameExample": "\u041f\u0440\u0438\u043c\u0435\u0440: \u0417\u0432\u0451\u0437\u0434\u043d\u044b\u0435 \u0432\u043e\u0439\u043d\u044b (\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f)", + "MessageItemsAdded": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b.", + "OptionNew": "\u041d\u043e\u0432\u043e\u0435...", + "LabelPlaylist": "\u041f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442:", + "AddToPlaylist": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442", + "HeaderAddToPlaylist": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u043f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442", + "Subtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044b", + "LabelTheme": "\u0422\u0435\u043c\u0430:", + "LabelDashboardTheme": "\u0422\u0435\u043c\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430:", + "SearchForSubtitles": "\u041f\u043e\u0438\u0441\u043a \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432", + "LabelLanguage": "\u042f\u0437\u044b\u043a:", + "Search": "\u041f\u043e\u0438\u0441\u043a", + "NoSubtitleSearchResultsFound": "\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e.", + "File": "\u0424\u0430\u0439\u043b", + "MessageAreYouSureDeleteSubtitles": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0441\u0443\u0431\u0438\u0442\u0440\u043e\u0432?", + "ConfirmDeletion": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f", + "MySubtitles": "\u041c\u043e\u0438 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b", + "MessageDownloadQueued": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438.", + "EditSubtitles": "\u041f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b", + "UnlockGuide": "\u0420\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043b\u0435\u0433\u0438\u0434", + "RefreshMetadata": "\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435", + "ReplaceExistingImages": "\u0417\u0430\u043c\u0435\u043d\u0430 \u0438\u043c\u0435\u044e\u0449\u0438\u0445\u0441\u044f \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432", + "ReplaceAllMetadata": "\u0417\u0430\u043c\u0435\u043d\u0430 \u0432\u0441\u0435\u0445 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445", + "SearchForMissingMetadata": "\u041f\u043e\u0438\u0441\u043a \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445", + "LabelRefreshMode": "\u0420\u0435\u0436\u0438\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f:", + "NoItemsFound": "\u041d\u0438\u043a\u0430\u043a\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e.", + "HeaderSaySomethingLike": "\u0421\u043a\u0430\u0436\u0438\u0442\u0435 \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435...", + "ButtonTryAgain": "\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043f\u043e\u043f\u044b\u0442\u043a\u0443", + "HeaderYouSaid": "\u0412\u044b \u0441\u043a\u0430\u0437\u0430\u043b\u0438...", + "MessageWeDidntRecognizeCommand": "\u0414\u0430\u043d\u043d\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0435 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u043d\u0430.", + "MessageIfYouBlockedVoice": "\u0415\u0441\u043b\u0438 \u043e\u0442\u043a\u0430\u0437\u0430\u043d\u043e \u0432 \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0435 \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e, \u043f\u0435\u0440\u0435\u0434 \u043d\u043e\u0432\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u043e\u0439 \u0432\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.", + "ValueDiscNumber": "\u0414\u0438\u0441\u043a {0}", + "Unrated": "\u0411\u0435\u0437 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438", + "Favorite": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435", + "Like": "\u041d\u0440\u0430\u0432\u0438\u0442\u0441\u044f", + "Dislike": "\u041d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f", + "RefreshDialogHelp": "\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u0438 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0443\u0441\u043b\u0443\u0433\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0432 \u041f\u0430\u043d\u0435\u043b\u0438 Emby Server.", + "Open": "\u041e\u0442\u043a\u0440\u044b\u0442\u044c", + "Play": "\u0412\u043e\u0441\u043f\u0440.", + "AddToPlayQueue": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f", + "Shuffle": "\u041f\u0435\u0440\u0435\u043c\u0435\u0448\u0430\u0442\u044c", + "Identify": "\u0420\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0442\u044c", + "EditImages": "\u041f\u0440\u0430\u0432\u0438\u0442\u044c \u0440\u0438\u0441\u0443\u043d\u043a\u0438", + "EditMetadata": "\u041f\u0440\u0430\u0432\u0438\u0442\u044c \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435", + "Convert": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c", + "Sync": "\u0421\u0438\u043d\u0445\u0440\u043e", + "InstantMix": "\u0410\u0432\u0442\u043e\u043c\u0438\u043a\u0441...", + "ViewAlbum": "\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0430\u043b\u044c\u0431\u043e\u043c", + "ViewArtist": "\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044f", + "QueueAllFromHere": "\u0412 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0432\u0441\u0435 \u043e\u0442\u0441\u044e\u0434\u0430", + "PlayAllFromHere": "\u0412\u043e\u0441\u043f\u0440. \u0432\u0441\u0435 \u043e\u0442\u0441\u044e\u0434\u0430", + "PlayFromBeginning": "\u0412\u043e\u0441\u043f\u0440. \u0441 \u043d\u0430\u0447\u0430\u043b\u0430", + "ResumeAt": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0441 {0}", + "RemoveFromPlaylist": "\u0418\u0437\u044a\u044f\u0442\u044c \u0438\u0437 \u043f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442\u0430", + "RemoveFromCollection": "\u0418\u0437\u044a\u044f\u0442\u044c \u0438\u0437 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438", + "Sort": "\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c", + "Trailer": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440", + "MarkPlayed": "\u041e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u043a\u0430\u043a \u0432\u043e\u0441\u043f\u0440-\u043e\u0435", + "MarkUnplayed": "\u041e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u043a\u0430\u043a \u043d\u0435\u0432\u043e\u0441\u043f\u0440-\u043e\u0435", + "GroupVersions": "\u0421\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u0438", + "PleaseSelectTwoItems": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0445\u043e\u0442\u044f \u0431\u044b \u0434\u0432\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.", + "TryMultiSelect": "\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043d\u0435\u0441\u0432\u044f\u0437\u043d\u043e\u0435 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435", + "TryMultiSelectMessage": "\u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u0440\u043e\u0441\u0442\u043e \u0449\u0451\u043b\u043a\u043d\u0438\u0442\u0435 \u0438 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0439\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u043c\u044b\u0448\u0438 \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u043f\u043e\u0441\u0442\u0435\u0440\u0435 \u0438 \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u0435 \u0442\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u044d\u0442\u043e!", + "HeaderConfirmRecordingCancellation": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u0437\u0430\u043f\u0438\u0441\u0438", + "MessageConfirmRecordingCancellation": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c?", + "Error": "\u041e\u0448\u0438\u0431\u043a\u0430", + "VoiceInput": "\u0413\u043e\u043b\u043e\u0441\u043e\u0432\u043e\u0439 \u0432\u0432\u043e\u0434", + "LabelContentType": "\u0422\u0438\u043f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:", + "LabelPath": "\u041f\u0443\u0442\u044c:", + "Playlists": "\u041f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442\u044b", + "LabelTitle": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435:", + "LabelOriginalTitle": "\u041e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435:", + "LabelSortTitle": "\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e:", + "LabelDateAdded": "\u0414\u0430\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f:", + "DateAdded": "\u0414\u0430\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f", + "DatePlayed": "\u0414\u0430\u0442\u0430 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f", + "ConfigureDateAdded": "\u041a\u0430\u043a \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u0442\u0443 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u041f\u0430\u043d\u0435\u043b\u0438 Emby Server \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u041c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438", + "LabelStatus": "\u0421\u0442\u0430\u0442\u0443\u0441:", + "LabelArtists": "\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438:", + "LabelArtistsHelp": "\u0414\u043b\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0442\u043e\u0447\u043a\u0443 \u0441 \u0437\u0430\u043f\u044f\u0442\u043e\u0439 (;)", + "HeaderAlbumArtists": "\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438 \u0430\u043b\u044c\u0431\u043e\u043c\u0430", + "LabelAlbumArtists": "\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438 \u0430\u043b\u044c\u0431\u043e\u043c\u0430:", + "LabelAlbum": "\u0410\u043b\u044c\u0431\u043e\u043c", + "Artists": "\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438", + "ImdbRating": "\u041e\u0446\u0435\u043d\u043a\u0430 IMDb", + "CommunityRating": "\u041e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043e\u0446\u0435\u043d\u043a\u0430", + "LabelCommunityRating": "\u041e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043e\u0446\u0435\u043d\u043a\u0430:", + "LabelCriticRating": "\u041e\u0446\u0435\u043d\u043a\u0430 \u043a\u0440\u0438\u0442\u0438\u043a\u043e\u0432:", + "CriticRating": "\u041e\u0446\u0435\u043d\u043a\u0430 \u043a\u0440\u0438\u0442\u0438\u043a\u043e\u0432", + "LabelWebsite": "\u0412\u0435\u0431\u0441\u0430\u0439\u0442:", + "LabelTagline": "\u041a\u043b\u044e\u0447\u0435\u0432\u0430\u044f \u0444\u0440\u0430\u0437\u0430:", + "LabelOverview": "\u041e\u0431\u0437\u043e\u0440:", + "LabelShortOverview": "\u041a\u0440\u0430\u0442\u043a\u0438\u0439 \u043e\u0431\u0437\u043e\u0440:", + "LabelReleaseDate": "\u0414\u0430\u0442\u0430 \u0432\u044b\u043f\u0443\u0441\u043a\u0430:", + "LabelYear": "\u0413\u043e\u0434:", + "LabelPlaceOfBirth": "\u041c\u0435\u0441\u0442\u043e \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:", + "Aired": "\u042d\u0444\u0438\u0440\u043d\u044b\u0439", + "LabelAirDays": "\u0414\u043d\u0438 \u044d\u0444\u0438\u0440\u0430:", + "LabelAirTime": "\u0412\u0440\u0435\u043c\u044f \u044d\u0444\u0438\u0440\u0430:", + "LabelRuntimeMinutes": "\u0414\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u043c\u0438\u043d:", + "LabelParentalRating": "\u0412\u043e\u0437\u0440\u0430\u0441\u0442\u043d\u0430\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f:", + "LabelCustomRating": "\u041f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u0430\u044f \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u043d\u0430\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f:", + "LabelOriginalAspectRatio": "\u0418\u0441\u0445\u043e\u0434\u043d\u043e\u0435 \u0441\u043e\u043e\u0442-\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d:", + "Label3DFormat": "\u0424\u043e\u0440\u043c\u0430\u0442 3D:", + "FormatValue": "\u0424\u043e\u0440\u043c\u0430\u0442: {0}", + "DownloadsValue": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0438: {0}", + "PerfectMatch": "\u041f\u043e\u043b\u043d\u043e\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435", + "EnableExternalVideoPlayers": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u0438 \u0432\u0438\u0434\u0435\u043e", + "EnableExternalVideoPlayersHelp": "\u041c\u0435\u043d\u044e \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432\u0438\u0434\u0435\u043e.", + "HeaderSpecialEpisodeInfo": "\u041e \u0441\u043f\u0435\u0446\u044d\u043f\u0438\u0437\u043e\u0434\u0435", + "LabelAirsBeforeSeason": "\u0421\u0435\u0437\u043e\u043d airs_before:", + "LabelAirsAfterSeason": "\u0421\u0435\u0437\u043e\u043d airs_after:", + "LabelAirsBeforeEpisode": "\u042d\u043f\u0438\u0437\u043e\u0434 airs_before:", + "HeaderExternalIds": "\u0412\u043d\u0435\u0448\u043d\u0438\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b:", + "HeaderDisplaySettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f", + "LabelDisplayOrder": "\u041f\u043e\u0440\u044f\u0434\u043e\u043a \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f:", + "Display": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", + "Countries": "\u0421\u0442\u0440\u0430\u043d\u044b", + "Genres": "\u0416\u0430\u043d\u0440\u044b", + "Studios": "\u0421\u0442\u0443\u0434\u0438\u0438", + "Tags": "\u0422\u0435\u0433\u0438", + "HeaderMetadataSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445", + "People": "\u041b\u044e\u0434\u0438", + "LabelMetadataDownloadLanguage": "\u0412\u044b\u0431\u043e\u0440 \u044f\u0437\u044b\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0433\u043e:", + "LabelLockItemToPreventChanges": "\u0417\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0440\u0435\u0442\u0438\u0442\u044c \u0431\u0443\u0434\u0443\u0449\u0438\u0435 \u043f\u0440\u0430\u0432\u043a\u0438", + "MessageLeaveEmptyToInherit": "\u041d\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0439\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u0442 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430, \u0438\u043b\u0438 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.", + "LabelCountry": "\u0421\u0442\u0440\u0430\u043d\u0430:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "\u0413\u043e\u0434 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:", + "LabelBirthDate": "\u0414\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:", + "LabelDeathDate": "\u0414\u0430\u0442\u0430 \u0441\u043c\u0435\u0440\u0442\u0438:", + "LabelEndDate": "\u041a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0434\u0430\u0442\u0430:", + "LabelSeasonNumber": "\u041d\u043e\u043c\u0435\u0440 \u0441\u0435\u0437\u043e\u043d\u0430:", + "LabelEpisodeNumber": "\u041d\u043e\u043c\u0435\u0440 \u044d\u043f\u0438\u0437\u043e\u0434\u0430:", + "LabelTrackNumber": "\u041d\u043e\u043c\u0435\u0440 \u0434\u043e\u0440\u043e\u0436\u043a\u0438:", + "LabelNumber": "\u041d\u043e\u043c\u0435\u0440:", + "LabelDiscNumber": "\u041d\u043e\u043c\u0435\u0440 \u0434\u0438\u0441\u043a\u0430:", + "LabelParentNumber": "\u0420\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043d\u043e\u043c\u0435\u0440:", + "SortName": "\u0421\u043e\u0440\u0442. \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e", + "ReleaseDate": "\u0414\u0430\u0442\u0430 \u0432\u044b\u043f\u0443\u0441\u043a\u0430", + "Continuing": "\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u044e\u0449\u0435\u0435\u0441\u044f", + "Ended": "\u041f\u0440\u0435\u043a\u0440\u0430\u0449\u0451\u043d\u043d\u043e\u0435", + "HeaderEnabledFields": "\u0412\u043a\u043b\u044e\u0447\u0451\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044f", + "HeaderEnabledFieldsHelp": "\u0421\u043d\u0438\u043c\u0438\u0442\u0435 \u0444\u043b\u0430\u0436\u043e\u043a, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0435 \u0438 \u0437\u0430\u0449\u0438\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 \u0438\u0437\u043c\u0435\u043d\u043d\u0435\u043d\u0438\u0439.", + "Backdrops": "\u0417\u0430\u0434\u043d\u0438\u043a\u0438", + "Images": "\u0420\u0438\u0441\u0443\u043d\u043a\u0438", + "Runtime": "\u0414\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c", + "ProductionLocations": "\u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434-\u043d\u044b\u0435 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0438", + "BirthLocation": "\u041c\u0435\u0441\u0442\u043e \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f", + "ParentalRating": "\u0412\u043e\u0437\u0440. \u043a\u0430\u0442.", + "PlayCount": "\u041a\u043e\u043b. \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439", + "Name": "\u0418\u043c\u044f", + "Overview": "\u041e\u0431\u0437\u043e\u0440", + "LabelType": "\u0422\u0438\u043f:", + "LabelPersonRole": "\u0420\u043e\u043b\u044c:", + "LabelPersonRoleHelp": "\u041f\u0440\u0438\u043c\u0435\u0440: \u0412\u043e\u0434\u0438\u0442\u0435\u043b\u044c \u0444\u0443\u0440\u0433\u043e\u043d\u0430 \u043c\u043e\u0440\u043e\u0436\u0435\u043d\u0449\u0438\u043a\u0430", + "Actor": "\u0410\u043a\u0442\u0451\u0440", + "Composer": "\u041a\u043e\u043c\u043f\u043e\u0437\u0438\u0442\u043e\u0440", + "Director": "\u0420\u0435\u0436\u0438\u0441\u0441\u0451\u0440", + "GuestStar": "\u041f\u0440\u0438\u0433\u043b. \u0430\u043a\u0442\u0451\u0440", + "Producer": "\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440", + "Writer": "\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0441\u0442", + "MessageNoSyncJobsFound": "\u0417\u0430\u0433\u0440\u0443\u0437\u043e\u043a \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e. \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043d\u043e\u043f\u043e\u043a \u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u043f\u043e \u0432\u0441\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e.", + "MessageNoDownloadsFound": "\u041d\u0435\u0442 \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u044b\u0445 \u0437\u0430\u0433\u0440\u0443\u0437\u043e\u043a. \u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u0430\u0436\u0430\u0432 \u00ab\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u00bb \u043f\u043e\u0432\u0441\u044e\u0434\u0443 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.", + "InstallingPackage": "\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f {0}", + "PackageInstallCompleted": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 {0} \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430.", + "PackageInstallFailed": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 {0} \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u0430.", + "PackageInstallCancelled": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 {0} \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430.", + "SeriesYearToPresent": "{0} - \u041d.\u0412.", + "ValueOneItem": "1 \u044d\u043b\u0435\u043c\u0435\u043d\u0442", + "ValueOneSong": "1 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u044f", + "ValueSongCount": "{0} \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438(\u0438\/\u0439)", + "ValueOneMovie": "1 \u0444\u0438\u043b\u044c\u043c", + "ValueMovieCount": "{0} \u0444\u0438\u043b\u044c\u043c(\u0430\/\u043e\u0432)", + "ValueOneSeries": "1 \u0441\u0435\u0440\u0438\u0430\u043b", + "ValueSeriesCount": "{0} \u0441\u0435\u0440\u0438\u0430\u043b(\u0430\/\u043e\u0432)", + "ValueOneEpisode": "1 \u044d\u043f\u0438\u0437\u043e\u0434", + "ValueEpisodeCount": "{0} \u044d\u043f\u0438\u0437\u043e\u0434(\u0430\/\u043e\u0432)", + "ValueOneGame": "1 \u0438\u0433\u0440\u0430", + "ValueGameCount": "{0} \u0438\u0433\u0440(\u044b)", + "ValueOneAlbum": "1 \u0430\u043b\u044c\u0431\u043e\u043c", + "ValueAlbumCount": "{0} \u0430\u043b\u044c\u0431\u043e\u043c(\u0430\/\u043e\u0432)", + "ValueOneMusicVideo": "1 \u043c\u0443\u0437\u044b\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0438\u0434\u0435\u043e", + "ValueMusicVideoCount": "{0} \u043c\u0443\u0437\u044b\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0432\u0438\u0434\u0435\u043e", + "ValueMinutes": "{0} \u043c\u0438\u043d", + "Albums": "\u0410\u043b\u044c\u0431\u043e\u043c\u044b", + "Songs": "\u041a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438", + "Books": "\u041a\u043d\u0438\u0433\u0438", + "HeaderAudioBooks": "\u0410\u0443\u0434\u0438\u043e\u043a\u043d\u0438\u0433\u0438", + "HeaderIdentifyItemHelp": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043e\u0434\u043d\u043e \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u043f\u043e\u0438\u0441\u043a\u0430. \u0418\u0437\u044b\u043c\u0438\u0442\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0440\u0430\u0441\u0442\u0438\u0442\u044c \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b.", + "PleaseEnterNameOrId": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0438\u043b\u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 ID.", + "MessageItemSaved": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d.", + "SearchResults": "\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u043e\u0438\u0441\u043a\u0430", + "ServerNameIsRestarting": "Emby Server - {0} \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f.", + "ServerNameIsShuttingDown": "Emby Server - {0} \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443.", + "HeaderDeleteItems": "\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432", + "ConfirmDeleteItems": "\u041f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043e\u043d \u0443\u0434\u0430\u043b\u0438\u0442\u0441\u044f \u0438 \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0438 \u0438\u0437 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438. \u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?", + "PleaseRestartServerName": "\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 Emby Server - {0}.", + "LabelSyncJobName": "\u0418\u043c\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0441\u0438\u043d\u0445\u0440-\u0438\u0438:", + "SyncingDots": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f...", + "ConvertingDots": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f...", + "LabelQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e:", + "LabelSyncNoTargetsHelp": "\u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430, \u043d\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f.", + "DownloadingDots": "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f...", + "HeaderSyncRequiresSub": "\u0414\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 Emby Premiere.", + "LearnMore": "\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435...", + "LabelProfile": "\u041f\u0440\u043e\u0444\u0438\u043b\u044c:", + "LabelBitrateMbps": "\u041f\u043e\u0442\u043e\u043a\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c, \u041c\u0431\u0438\u0442\/\u0441:", + "ConvertUnwatchedVideosOnly": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e", + "SyncUnwatchedVideosOnly": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043d\u0435\u043f\u0440\u043e\u0441\u043c-\u044b\u0435 \u0432\u0438\u0434\u0435\u043e", + "ConvertUnwatchedVideosOnlyHelp": "\u0422\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u044b", + "SyncUnwatchedVideosOnlyHelp": "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c-\u044b\u0435 \u0432\u0438\u0434\u0435\u043e, \u0430 \u043f\u0440\u043e\u0441\u043c-\u044b\u0435 \u0438\u0437\u044b\u043c\u0430\u044e\u0442\u0441\u044f \u0441 \u0443\u0441\u0442\u0440-\u0432\u0430.", + "AutomaticallySyncNewContent": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435", + "AutomaticallySyncNewContentHelp": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u0432 \u044d\u0442\u0443 \u043f\u0430\u043f\u043a\u0443, \u0430\u0432\u0442\u043e-\u043a\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0443\u0441\u0442\u0440-\u0432\u043e.", + "AutomaticallyConvertNewContent": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435", + "AutomaticallyConvertNewContentHelp": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u0432 \u0434\u0430\u043d\u043d\u0443\u044e \u043f\u0430\u043f\u043a\u0443, \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u043e.", + "LabelItemLimit": "\u041b\u0438\u043c\u0438\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432:", + "ConvertItemLimitHelp": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c\u0441\u044f.", + "DownloadItemLimitHelp": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f.", + "PleaseSelectDeviceToSyncTo": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e, \u043a\u0443\u0434\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c.", + "Screenshots": "\u0421\u043d\u0438\u043c\u043a\u0438 \u044d\u043a\u0440\u0430\u043d\u0430", + "MoveRight": "\u0414\u0432\u0438\u0433\u0430\u0442\u044c \u0432\u043f\u0440\u0430\u0432\u043e", + "MoveLeft": "\u0414\u0432\u0438\u0433\u0430\u0442\u044c \u0432\u043b\u0435\u0432\u043e", + "ConfirmDeleteImage": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0440\u0438\u0441\u0443\u043d\u043e\u043a?", + "HeaderEditImages": "\u041f\u0440\u0430\u0432\u0438\u0442\u044c \u0440\u0438\u0441\u0443\u043d\u043a\u0438", + "Settings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b", + "ShowIndicatorsFor": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043a\u0438 \u0434\u043b\u044f:", + "NewEpisodes": "\u041d\u043e\u0432\u044b\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b", + "Episodes": "\u042d\u043f\u0438\u0437\u043e\u0434\u044b", + "HDPrograms": "HD-\u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438", + "Programs": "\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0438", + "LiveBroadcasts": "\u041f\u0440\u044f\u043c\u044b\u0435 \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438", + "Premieres": "\u041f\u0440\u0435\u043c\u044c\u0435\u0440\u044b", + "RepeatEpisodes": "\u041f\u043e\u0432\u0442\u043e\u0440 \u044d\u043f\u0438\u0437\u043e\u0434\u043e\u0432", + "DvrSubscriptionRequired": "\u0414\u043b\u044f \u0432\u0438\u0434\u0435\u043e\u0440\u0435\u043a\u043e\u0440\u0434\u0435\u0440\u0430 Emby \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 Emby Premiere.", + "HeaderCancelRecording": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c", + "CancelRecording": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c", + "HeaderKeepRecording": "\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438", + "HeaderCancelSeries": "\u041e\u0442\u043c\u0435\u043d\u0430 \u0441\u0435\u0440\u0438\u0430\u043b\u0430", + "HeaderKeepSeries": "\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0438\u0430\u043b\u0430", + "HeaderLearnMore": "\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435...", + "DeleteMedia": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435", + "SeriesSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0435\u0440\u0438\u0430\u043b\u0430", + "HeaderRecordingOptions": "\u041e\u043f\u0446\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0438", + "CancelSeries": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b", + "DoNotRecord": "\u041d\u0435 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c", + "HeaderSeriesOptions": "\u041e\u043f\u0446\u0438\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0430", + "LabelChannels": "\u041a\u0430\u043d\u0430\u043b\u044b:", + "ChannelNameOnly": "\u0422\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u043d\u0430\u043b {0}", + "Anytime": "\u0412 \u043b\u044e\u0431\u043e\u0435 \u0432\u0440\u0435\u043c\u044f", + "AnyLanguage": "\u041b\u044e\u0431\u043e\u0439 \u044f\u0437\u044b\u043a", + "AroundTime": "\u041e\u043a\u043e\u043b\u043e {0}", + "All": "\u0412\u0441\u0435", + "AllChannels": "\u0412\u0441\u0435 \u043a\u0430\u043d\u0430\u043b\u044b", + "LabelRecord": "\u0417\u0430\u043f\u0438\u0441\u044c:", + "NewEpisodesOnly": "\u0422\u043e\u043b\u044c\u043a\u043e \u043d\u043e\u0432\u044b\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b", + "AllEpisodes": "\u0412\u0441\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b", + "LabelStartWhenPossible": "\u041d\u0430\u0447\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e:", + "LabelStopWhenPossible": "\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e:", + "MinutesBefore": "\u043c\u0438\u043d\u0443\u0442(\u0443\/\u044b) \u0434\u043e", + "MinutesAfter": "\u043c\u0438\u043d\u0443\u0442(\u0443\/\u044b) \u043f\u043e\u0441\u043b\u0435", + "SkipEpisodesAlreadyInMyLibrary": "\u041d\u0435 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u044d\u043f\u0438\u0437\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0436\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043c\u043e\u0435\u0439 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435", + "SkipEpisodesAlreadyInMyLibraryHelp": "\u042d\u043f\u0438\u0437\u043e\u0434\u044b \u0431\u0443\u0434\u0443\u0442 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u043e\u043c\u0435\u0440\u043e\u0432 \u0441\u0435\u0437\u043e\u043d\u043e\u0432 \u0438 \u044d\u043f\u0438\u0437\u043e\u0434\u043e\u0432, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0438 \u0438\u043c\u0435\u044e\u0442\u0441\u044f.", + "LabelKeepUpTo": "\u0425\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u043e:", + "AsManyAsPossible": "\u041a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435", + "DefaultErrorMessage": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.", + "LabelKeep:": "\u0425\u0440\u0430\u043d\u0438\u0442\u044c:", + "UntilIDelete": "\u041f\u043e\u043a\u0430 \u044f \u043d\u0435 \u0443\u0434\u0430\u043b\u044e", + "UntilSpaceNeeded": "\u041f\u043e\u043a\u0430 \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043c\u0435\u0441\u0442\u043e", + "Categories": "\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438", + "Sports": "\u0421\u043f\u043e\u0440\u0442", + "News": "\u041d\u043e\u0432\u043e\u0441\u0442\u0438", + "Movies": "\u0424\u0438\u043b\u044c\u043c\u044b", + "Kids": "\u0414\u0435\u0442\u044f\u043c", + "EnableColorCodedBackgrounds": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0446\u0432\u0435\u0442\u043e\u0432\u043e\u0439 \u0444\u043e\u043d", + "SortChannelsBy": "\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043d\u0430\u043b\u044b \u043f\u043e:", + "RecentlyWatched": "\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u043e\u0435", + "ChannelNumber": "\u041d\u043e\u043c\u0435\u0440 \u043a\u0430\u043d\u0430\u043b\u0430", + "HeaderBenefitsEmbyPremiere": "\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "\u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u043e\u0434\u043d\u043e\u0439 \u043c\u0438\u043d\u0443\u0442\u043e\u0439 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0438\u043c \u0432\u0430\u0441 \u0437\u0430 \u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043d\u0438\u0435 Emby.", + "HeaderTryPlayback": "\u041e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435", + "HowDidYouPay": "\u041a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0432\u044b \u043e\u043f\u043b\u0430\u0442\u0438\u043b\u0438?", + "IHaveEmbyPremiere": "\u0423 \u043c\u0435\u043d\u044f \u0438\u043c\u0435\u0435\u0442\u0441\u044f Emby Premiere", + "IPurchasedThisApp": "\u042f \u043f\u0440\u0438\u043e\u0431\u0440\u0451\u043b \u0434\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435", + "ButtonRestorePreviousPurchase": "\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0442\u0435\u043d\u0438\u0435", + "ButtonUnlockWithPurchase": "\u0420\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u043e\u043f\u043b\u0430\u0442\u044b", + "ButtonUnlockPrice": "\u0420\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere \u043d\u0430 \u043c\u0435\u0441\u044f\u0446 {0}", + "HeaderAlreadyPaid": "\u0423\u0436\u0435 \u043e\u043f\u043b\u0430\u0442\u0438\u043b\u0438?", + "ButtonPlayOneMinute": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043e\u0434\u043d\u0443 \u043c\u0438\u043d\u0443\u0442\u0443", + "PlaceFavoriteChannelsAtBeginning": "\u0420\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043a\u0430\u043d\u0430\u043b\u044b \u0432 \u043d\u0430\u0447\u0430\u043b\u0435", + "HeaderUnlockFeature": "\u0420\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0443", + "MessageDidYouKnowCinemaMode": "\u0417\u043d\u0430\u0435\u0442\u0435 \u043b\u0438 \u0432\u044b, \u0447\u0442\u043e \u0441 Emby Premiere \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0432\u044b\u0441\u0438\u0442\u044c \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u043c\u0438 \u0420\u0435\u0436\u0438\u043c\u0443 \u043a\u0438\u043d\u043e\u0437\u0430\u043b\u0430?", + "MessageDidYouKnowCinemaMode2": "\u0420\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0437\u0430\u043b\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0432\u0430\u043c \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0433\u043e \u0437\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043b\u0430 \u0441 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u0430\u043c\u0438 \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0430\u043c\u0438 \u043f\u0435\u0440\u0435\u0434 \u0444\u0438\u043b\u044c\u043c\u043e\u043c.", + "HeaderPlayMyMedia": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043c\u043e\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435", + "HeaderDiscoverEmbyPremiere": "\u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0434\u043b\u044f \u0441\u0435\u0431\u044f Emby Premiere", + "Items": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u044b", + "OneChannel": "\u041e\u0434\u0438\u043d \u043a\u0430\u043d\u0430\u043b", + "ConfirmRemoveDownload": "\u0418\u0437\u044a\u044f\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443?", + "RemoveDownload": "\u0418\u0437\u044a\u044f\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443", + "KeepDownload": "\u0425\u0440\u0430\u043d\u0438\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u043e\u0435", + "AddedOnValue": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e {0}", + "RemovingFromDevice": "\u0418\u0437\u044b\u043c\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430", + "KeepOnDevice": "\u0425\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435", + "CancelDownload": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443", + "SyncJobItemStatusReadyToTransfer": "\u0413\u043e\u0442\u043e\u0432\u043e \u043a \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0443", + "SyncJobItemStatusSyncedMarkForRemoval": "\u0418\u0437\u044b\u043c\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430", + "SyncJobItemStatusQueued": "\u0412 \u043e\u0447\u0435\u0440\u0435\u0434\u0438", + "SyncJobItemStatusConverting": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f", + "SyncJobItemStatusTransferring": "\u041f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u0441\u044f", + "SyncJobItemStatusSynced": "\u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043e", + "SyncJobItemStatusFailed": "\u041d\u0435\u0443\u0434\u0430\u0447\u043d\u043e", + "SyncJobItemStatusRemovedFromDevice": "\u0418\u0437\u044a\u044f\u0442\u043e \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430", + "SyncJobItemStatusCancelled": "\u041e\u0442\u043c\u0435\u043d\u0435\u043d\u043e", + "Retry": "\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c", + "HeaderMyDevice": "\u041c\u043e\u0451 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e", + "Continue": "\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c", + "ContinueInSecondsValue": "\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 {0} \u0441.", + "HeaderRemoteControl": "\u0423\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435", + "Disconnect": "\u0420\u0430\u0437\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c\u0441\u044f", + "EnableDisplayMirroring": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f", + "HeaderPlayOn": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435", + "Quality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e", + "Auto": "\u0410\u0432\u0442\u043e", + "AndroidUnlockRestoreHelp": "\u0427\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0443\u044e \u043f\u043e\u043a\u0443\u043f\u043a\u0443, \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u044b \u0432\u043e\u0448\u043b\u0438 \u0432 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0441 \u0442\u043e\u0439 \u0436\u0435 \u0441\u0430\u043c\u043e\u0439 \u0443\u0447\u0451\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u044c\u044e Google (\u0438\u043b\u0438 Amazon), \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043f\u043e\u043a\u0443\u043f\u043a\u0443 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u043c\u0430\u0433\u0430\u0437\u0438\u043d \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u0438 \u043d\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d \u043a\u0430\u043a\u0438\u043c-\u043b\u0438\u0431\u043e \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u043c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c \u0432 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0443. \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0447\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0443\u044e \u043f\u043e\u043a\u0443\u043f\u043a\u0443.", + "AspectRatio": "\u0421\u043e\u043e\u0442-\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d", + "Original": "\u0418\u0441\u0445\u043e\u0434\u043d\u043e\u0435", + "Fill": "\u0417\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435", + "BestFit": "\u0410\u0432\u0442\u043e\u043f\u043e\u0434\u0431\u043e\u0440", + "MessageNoServersAvailableToConnect": "\u041d\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f. \u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u043a \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e\u043c\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u0443 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443, \u0442\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u043f\u0440\u0438\u043d\u044f\u043b\u0438 \u0435\u0433\u043e \u043d\u0438\u0436\u0435, \u0438\u043b\u0438 \u0449\u0451\u043b\u043a\u043d\u0443\u0432 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432 \u044d-\u043f\u043e\u0447\u0442\u0435.", + "MessagePlayAccessRestricted": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043e. \u0417\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f\u043c\u0438. \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044c \u043a \u0432\u0430\u0448\u0435\u043c\u0443 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0443 Emby Server.", + "Accept": "\u041f\u0440\u0438\u043d\u044f\u0442\u044c", + "Reject": "\u041e\u0442\u043a\u043b\u043e\u043d\u0438\u0442\u044c", + "Connect": "\u041f\u043e\u0434\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c\u0441\u044f", + "HeaderMyMedia": "\u041c\u043e\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435", + "HeaderMyMediaSmall": "\u041c\u043e\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435 (\u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e)", + "LatestFromLibrary": "\u041d\u043e\u0432\u0435\u0439\u0448\u0435\u0435: {0}", + "ContinueWatching": "\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430", + "HeaderLatestChannelMedia": "\u041d\u043e\u0432\u0435\u0439\u0448\u0435\u0435 \u0438\u0437 \u043a\u0430\u043d\u0430\u043b\u043e\u0432", + "HeaderContinueWatching": "\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430", + "HeaderContinueListening": "\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u043d\u0438\u044f", + "HeaderActiveRecordings": "\u0410\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438", + "HeaderLatestRecordings": "\u041d\u043e\u0432\u0435\u0439\u0448\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438", + "LabelSyncTo": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0441:", + "LabelConvertTo": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0432:", + "Next": "\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435", + "LabelSource": "\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a:", + "LabelVersion": "\u0412\u0435\u0440\u0441\u0438\u044f:", + "AllLanguages": "\u0412\u0441\u0435 \u044f\u0437\u044b\u043a\u0438", + "Previous": "\u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0435", + "HeaderNextUp": "\u041e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0435", + "HeaderLatestFrom": "\u041d\u043e\u0432\u0435\u0439\u0448\u0435\u0435 \u0438\u0437 {0}", + "LabelHomeScreenSectionValue": "\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 - \u0440\u0430\u0437\u0434\u0435\u043b {0}:", + "SettingsSaved": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b.", + "None": "\u041d\u0438\u0447\u0435\u0433\u043e", + "More": "\u0415\u0449\u0451...", + "Up": "\u0412\u0432\u0435\u0440\u0445", + "Down": "\u0412\u043d\u0438\u0437", + "Home": "\u0413\u043b\u0430\u0432\u043d\u043e\u0435", + "Favorites": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435", + "HeaderHomeScreen": "\u0413\u043b\u0430\u0432\u043d\u044b\u0439 \u044d\u043a\u0440\u0430\u043d", + "HeaderLatestChannelItems": "\u041d\u043e\u0432\u0435\u0439\u0448\u0435\u0435 \u0438\u0437 \u043a\u0430\u043d\u0430\u043b\u043e\u0432", + "HeaderLibraryOrder": "\u041f\u043e\u0440\u044f\u0434\u043e\u043a \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a", + "HideWatchedContentFromLatestMedia": "\u0421\u043a\u0440\u044b\u0442\u044c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0438\u0437 \u041d\u043e\u0432\u0435\u0439\u0448\u0438\u0445 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445", + "HeaderOnNow": "\u0412 \u044d\u0444\u0438\u0440\u0435", + "HeaderPlaybackError": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f", + "PlaybackErrorNotAllowed": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0432\u044b \u043d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0447\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435. \u0417\u0430 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044c \u043a \u0441\u0432\u043e\u0435\u043c\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u043c\u0443 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0443.", + "PlaybackErrorNoCompatibleStream": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0432 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435 \u0438\u043b\u0438 \u0437\u0430 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044c \u043a \u0441\u0432\u043e\u0435\u043c\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u043c\u0443 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0443.", + "PlaybackErrorPlaceHolder": "\u0412\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0434\u0438\u0441\u043a, \u0447\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0434\u0430\u043d\u043d\u043e\u0435 \u0432\u0438\u0434\u0435\u043e.", + "Guide": "\u0422\u0435\u043b\u0435\u0433\u0438\u0434", + "Suggestions": "\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u043e\u0435", + "HeaderFavoriteCollections": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438", + "HeaderFavoritePlaylists": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442\u044b", + "Collections": "\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438", + "LabelSelectFolderGroups": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u044c \u0430\u0441\u043f\u0435\u043a\u0442\u043e\u0432 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: \u041a\u0438\u043d\u043e, \u041c\u0443\u0437\u044b\u043a\u0430 \u0438 \u0422\u0412) \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u0438\u0437 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043f\u0430\u043f\u043e\u043a:", + "LabelSelectFolderGroupsHelp": "\u041f\u0430\u043f\u043a\u0438, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043d\u044f\u0442\u044b \u0444\u043b\u0430\u0436\u043a\u0438, \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0432 \u0438\u0445 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0430\u0441\u043f\u0435\u043a\u0442\u0430\u0445.", + "Folders": "\u041f\u0430\u043f\u043a\u0438", + "DisplayInOtherHomeScreenSections": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0430\u0445 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430 (\u043d\u043f\u0440., \u043d\u043e\u0432\u0435\u0439\u0448\u0438\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0438 \u0442.\u043f.)", + "DisplayInMyMedia": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u044d\u043a\u0440\u0430\u043d\u0435", + "Shows": "\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0438", + "HeaderLibraryFolders": "\u041c\u0435\u0434\u0438\u0430\u0442\u0435\u0447\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438", + "HeaderTermsOfPurchase": "\u0423\u0441\u043b\u043e\u0432\u0438\u044f \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0435\u0442\u0435\u043d\u0438\u044f", + "PrivacyPolicy": "\u041f\u043e\u043b\u0438\u0442\u0438\u043a\u0430 \u043a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438", + "TermsOfUse": "\u0423\u0441\u043b\u043e\u0432\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f", + "RepeatMode": "\u0420\u0435\u0436\u0438\u043c \u043f\u043e\u0432\u0442\u043e\u0440\u0430", + "RepeatOne": "\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u0440\u0430\u0437", + "RepeatAll": "\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u0432\u0441\u0435", + "LabelDefaultScreen": "\u042d\u043a\u0440\u0430\u043d \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e:", + "ConfirmEndPlayerSession": "\u0412\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 Emby \u043d\u0430 {0}?", + "Yes": "\u0414\u0430", + "No": "\u041d\u0435\u0442", + "LiveTV": "\u042d\u0444\u0438\u0440", + "Schedule": "\u0420\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0435", + "Recordings": "\u0417\u0430\u043f\u0438\u0441\u0438", + "MarkWatched": "\u041e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u043a\u0430\u043a \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u043e\u0435", + "ScanForNewAndUpdatedFiles": "\u0421\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0438 \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432", + "DirectStreamHelp1": "\u041c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c \u0432 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0438 \u0442\u0438\u043f\u0430 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 (H.264, AC3, \u0438 \u0442.\u0434.), \u043d\u043e \u0432 \u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u043c \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 (.mkv, .avi, .wmv \u0438 \u0442.\u0434.). \u0412\u0438\u0434\u0435\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u043e \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0434 \u0435\u0433\u043e \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0435\u0439 \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e.", + "DirectStreamHelp2": "\u041f\u0440\u0438 \u043f\u0440\u044f\u043c\u043e\u0439 \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438 \u0444\u0430\u0439\u043b\u0430 \u0440\u0430\u0441\u0445\u043e\u0434\u0443\u0435\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u043c\u0430\u043b\u043e \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043c\u043e\u0449\u043d\u043e\u0441\u0442\u0438 \u0431\u0435\u0437 \u043f\u043e\u0442\u0435\u0440\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u0438\u0434\u0435\u043e.", + "MediaIsBeingConverted": "\u041c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0442\u0441\u044f \u0432 \u0444\u043e\u0440\u043c\u0430\u0442, \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0439 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u044d\u0442\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435.", + "StatsForNerds": "\u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 \u0434\u043b\u044f \u0443\u043c\u043d\u0438\u043a\u043e\u0432", + "LabelReasonForTranscoding": "\u041f\u0440\u0438\u0447\u0438\u043d\u0430 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f:", + "DirectPlaying": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e", + "DirectStreaming": "\u0422\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e", + "Transcoding": "\u041f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u0442\u0441\u044f", + "ContainerBitrateExceedsLimit": "\u041f\u043e\u0442\u043e\u043a\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0435\u0432\u044b\u0441\u0438\u043b\u0430 \u043f\u0440\u0435\u0434\u0435\u043b.", + "VideoCodecNotSupported": "\u0412\u0438\u0434\u0435\u043e\u043a\u043e\u0434\u0435\u043a \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "AudioCodecNotSupported": "\u0410\u0443\u0434\u0438\u043e\u043a\u043e\u0434\u0435\u043a \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "SubtitleCodecNotSupported": "\u0424\u043e\u0440\u043c\u0430\u0442 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "DirectPlayError": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f", + "ContainerNotSupported": "\u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "VideoLevelNotSupported": "\u0423\u0440\u043e\u0432\u0435\u043d\u044c \u0432\u0438\u0434\u0435\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "AudioBitrateNotSupported": "\u041f\u043e\u0442\u043e\u043a\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0430\u0443\u0434\u0438\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "AudioChannelsNotSupported": "\u0410\u0443\u0434\u0438\u043e\u043a\u0430\u043d\u0430\u043b\u044b \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f", + "VideoResolutionNotSupported": "\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0435\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "AudioProfileNotSupported": "\u0410\u0443\u0434\u0438\u043e \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "AudioSampleRateNotSupported": "\u0427\u0430\u0441\u0442\u043e\u0442\u0430 \u0434\u0438\u0441\u043a\u0440\u0435\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0430\u0443\u0434\u0438\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "AnamorphicVideoNotSupported": "\u0410\u043d\u0430\u043c\u043e\u0440\u0444\u043d\u043e\u0435 \u0432\u0438\u0434\u0435\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "InterlacedVideoNotSupported": "\u0427\u0435\u0440\u0435\u0441\u0441\u0442\u0440\u043e\u0447\u043d\u043e\u0435 \u0432\u0438\u0434\u0435\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "SecondaryAudioNotSupported": "\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0430\u0443\u0434\u0438\u043e \u0434\u043e\u0440\u043e\u0436\u0435\u043a \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "ErrorRemovingEmbyConnectAccount": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0443\u0447\u0451\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 Emby Connect. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443.", + "HeaderEmbyAccountRemoved": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c Emby \u0438\u0437\u044a\u044f\u0442\u0430", + "MessageEmbyAccontRemoved": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c Emby \u0431\u044b\u043b\u0430 \u0438\u0437\u044a\u044f\u0442\u0430 \u0443 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f", + "HeaderInvitationSent": "\u041f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e", + "MessageInvitationSentToUser": "\u041f\u0438\u0441\u044c\u043c\u043e \u0431\u044b\u043b\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u043a {0}, \u0441 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043d\u044f\u0442\u044c \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f.", + "MessageInvitationSentToNewUser": "\u041f\u0438\u0441\u044c\u043c\u043e \u0431\u044b\u043b\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u043a {0}, \u0441 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 Emby.", + "GuestUserNotFound": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0438\u043c\u044f \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043e \u0432\u0435\u0440\u043d\u043e \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443, \u0438\u043b\u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0432\u0432\u0435\u0441\u0442\u0438 \u0435\u0433\u043e \u0430\u0434\u0440\u0435\u0441 \u042d-\u043f\u043e\u0447\u0442\u044b.", + "ErrorReachingEmbyConnect": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u0434\u043e\u0441\u0442\u0438\u0447\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Emby Connect. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443.", + "ErrorAddingEmbyConnectAccount1": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0443\u0447\u0451\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 Emby Connect. \u0421\u043e\u0437\u0434\u0430\u043b\u0438 \u043b\u0438 \u0432\u044b \u0443\u0447\u0435\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c Emby? \u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0439\u0442\u0435\u0441\u044c \u043d\u0430 {0}.", + "ErrorAddingEmbyConnectAccount2": "\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0432\u0441\u0451 \u0435\u0449\u0451 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u043e\u0442\u043f\u0440\u0430\u0432\u044c\u0442\u0435 \u043f\u0438\u0441\u044c\u043c\u043e \u043d\u0430 {0} \u0441 \u0430\u0434\u0440\u0435\u0441\u0430 \u042d-\u043f\u043e\u0447\u0442\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0432 \u0443\u0447\u0435\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 Emby.", + "ErrorAddingGuestAccount1": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0443\u0447\u0451\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 Emby Connect. \u0421\u043e\u0437\u0434\u0430\u043b \u043b\u0438 \u0432\u0430\u0448 \u0433\u043e\u0441\u0442\u044c \u0443\u0447\u0435\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c Emby? \u041e\u043d \u0441\u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 {0}.", + "ErrorAddingGuestAccount2": "\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0432\u0441\u0451 \u0435\u0449\u0451 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u043e\u0442\u043f\u0440\u0430\u0432\u044c\u0442\u0435 \u043f\u0438\u0441\u044c\u043c\u043e \u043d\u0430 {0}, \u0438 \u043f\u0440\u0438\u0432\u0435\u0434\u0438\u0442\u0435 \u0441\u0432\u043e\u0439 \u0430\u0434\u0440\u0435\u0441 \u042d-\u043f\u043e\u0447\u0442\u044b, \u043d\u0430\u0440\u044f\u0434\u0443 \u0441 \u0438\u0445 \u0430\u0434\u0440\u0435\u0441\u0430\u043c\u0438.", + "MessageEmbyAccountAdded": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c Emby \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f", + "MessagePendingEmbyAccountAdded": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c Emby \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041f\u0438\u0441\u044c\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0443 \u0443\u0447\u0451\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438. \u041f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c, \u0449\u0451\u043b\u043a\u043d\u0443\u0432 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432 \u043f\u0438\u0441\u044c\u043c\u0435.", + "HeaderEmbyAccountAdded": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c Emby \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430", + "LabelSubtitlePlaybackMode": "\u0420\u0435\u0436\u0438\u043c \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432:", + "ErrorDeletingItem": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441 Emby Server. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435, \u0447\u0442\u043e \u0443 Emby Server \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043a\u0443 \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443.", + "NoSubtitles": "\u0411\u0435\u0437 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432", + "Default": "\u0423\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u0435", + "Absolute": "\u0410\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u0439", + "Smart": "\u0423\u043c\u043d\u044b\u0439", + "Small": "\u041c\u0435\u043b\u043a\u0438\u0439", + "Smaller": "\u041f\u043e\u043c\u0435\u043d\u044c\u0448\u0435", + "Medium": "\u0421\u0440\u0435\u0434\u043d\u0438\u0439", + "Large": "\u041a\u0440\u0443\u043f\u043d\u044b\u0439", + "ExtraLarge": "\u041e\u0447\u0435\u043d\u044c \u043a\u0440\u0443\u043f\u043d\u044b\u0439", + "OnlyForcedSubtitles": "\u0422\u043e\u043b\u044c\u043a\u043e \u0444\u043e\u0440\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b", + "AlwaysPlaySubtitles": "\u0412\u0441\u0435\u0433\u0434\u0430 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0441 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0430\u043c\u0438", + "DefaultSubtitlesHelp": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u0444\u043b\u0430\u0433\u0430\u043c\u0438 \"\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e\" \u0438 \"\u0424\u043e\u0440\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435\" \u0432\u043e \u0432\u043d\u0435\u0434\u0440\u0451\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445. \u042f\u0437\u044b\u043a\u043e\u0432\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043e\u043f\u0446\u0438\u0439.", + "SmartSubtitlesHelp": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044b, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u044f\u0437\u044b\u043a\u0430, \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f, \u0435\u0441\u043b\u0438 \u0430\u0443\u0434\u0438\u043e \u043d\u0430 \u0438\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u043d\u043e\u043c \u044f\u0437\u044b\u043a\u0435.", + "HeaderSubtitleSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432", + "HeaderSubtitleAppearance": "\u041e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u0435 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432", + "OnlyForcedSubtitlesHelp": "\u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b \u0431\u0443\u0434\u0443\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u043e\u0440\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b.", + "AlwaysPlaySubtitlesHelp": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044b, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u044f\u0437\u044b\u043a\u0430, \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u044f\u0437\u044b\u043a\u0430 \u0430\u0443\u0434\u0438\u043e.", + "NoSubtitlesHelp": "\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f. \u041e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0432\u0441\u0435 \u0435\u0449\u0451 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f.", + "LabelPreferredSubtitleLanguage": "\u0412\u044b\u0431\u043e\u0440 \u044f\u0437\u044b\u043a\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432:", + "LabelTextSize": "\u0420\u0430\u0437\u043c\u0435\u0440 \u0442\u0435\u043a\u0441\u0442\u0430:", + "TheseSettingsAffectSubtitlesOnThisDevice": "\u042d\u0442\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435", + "LabelDropShadow": "\u041e\u043a\u0430\u043d\u0442\u043e\u0432\u043a\u0430:", + "LabelTextBackgroundColor": "\u0426\u0432\u0435\u0442 \u0444\u043e\u043d\u0430 \u0442\u0435\u043a\u0441\u0442\u0430:", + "LabelWindowBackgroundColor": "\u0426\u0432\u0435\u0442 \u0444\u043e\u043d\u0430:", + "LabelFont": "\u0428\u0440\u0438\u0444\u0442:", + "LabelTextColor": "\u0426\u0432\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0430:", + "Raised": "\u0412\u044b\u043f\u0443\u043a\u043b\u0430\u044f", + "Depressed": "\u0412\u0434\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f", + "Uniform": "\u041e\u0434\u043d\u043e\u0440\u043e\u0434\u043d\u0430\u044f", + "DropShadow": "\u0422\u0435\u043d\u0435\u0432\u0430\u044f", + "SmallCaps": "\u041c\u0430\u043b\u044b\u0435 \u043f\u0440\u043e\u043f\u0438\u0441\u043d\u044b\u0435", + "SubtitleAppearanceSettingsDisclaimer": "\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u044b \u043a \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0430\u043c (PGS, DVD \u0438 \u0442.\u0434.) \u0438\u043b\u0438 \u043a \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u044e\u0442 \u0432\u043d\u0435\u0434\u0440\u0451\u043d\u043d\u044b\u0435 \u0441\u0432\u043e\u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0441\u0442\u0438\u043b\u0438 (ASS\/SSA).", + "LabelBurnSubtitles": "\u0412\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432:", + "OnlyImageFormats": "\u0422\u043e\u043b\u044c\u043a\u043e \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u044b (VOBSUB, PGS, SUB\/IDX \u0438 \u0442.\u0434.)", + "Normal": "\u041e\u0431\u044b\u0447\u043d\u044b\u0439", + "BurnSubtitlesHelp": "\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f, \u0434\u043e\u043b\u0436\u0435\u043d \u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u043f\u0440\u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0432\u0438\u0434\u0435\u043e \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432. \u0418\u0437\u0431\u0435\u0433\u0430\u043d\u0438\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 \u0443\u043b\u0443\u0447\u0448\u0438\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u00ab\u0410\u0432\u0442\u043e\u00bb \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, VOBSUB, PGS, SUB\/IDX \u0438 \u0442.\u043f.), \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 ASS\/SSA.", + "AllComplexFormats": "\u0412\u0441\u0435 \u043a\u043e\u043c\u043b\u0435\u043a\u0441\u043d\u044b\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u044b (ASS, SSA, VOBSUB, PGS, SUB\/IDX \u0438 \u0442.\u0434.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "\u042d\u0442\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u044b \u043a \u043b\u044e\u0431\u043e\u043c\u0443 Chromecast-\u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044e \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u043c\u0443 \u0434\u0430\u043d\u043d\u044b\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c.", + "HeaderWaitingForWifi": "\u0412 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438 WiFi", + "WifiRequiredToDownload": "WiFi-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438.", + "HeaderDownloadSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438", + "Hide": "\u0421\u043a\u0440\u044b\u0442\u044c", + "HeaderStartNow": "\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e", + "HeaderNextVideoPlayingInValue": "\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u0432\u0438\u0434\u0435\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 {0}", + "HeaderNextEpisodePlayingInValue": "\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u044d\u043f\u0438\u0437\u043e\u0434 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 {0}", + "HeaderSecondsValue": "{0} \u0441", + "AudioBitDepthNotSupported": "\u0420\u0430\u0437\u0440\u044f\u0434\u043d\u043e\u0441\u0442\u044c \u0430\u0443\u0434\u0438\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "VideoProfileNotSupported": "\u0412\u0438\u0434\u0435\u043e \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "VideoFramerateNotSupported": "\u0427\u0430\u0441\u0442\u043e\u0442\u0430 \u043a\u0430\u0434\u0440\u043e\u0432 \u0432\u0438\u0434\u0435\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "VideoBitDepthNotSupported": "\u0413\u043b\u0443\u0431\u0438\u043d\u0430 \u0446\u0432\u0435\u0442\u0430 \u0432\u0438\u0434\u0435\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "RefFramesNotSupported": "\u0427\u0438\u0441\u043b\u043e \u043e\u043f\u043e\u0440\u043d\u044b\u0445 \u043a\u0430\u0434\u0440\u043e\u0432 \u0432\u0438\u0434\u0435\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "ErrorConnectServerUnreachable": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0448\u0435\u043d\u043d\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438. \u0412\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u0432\u044f\u0437\u0430\u0442\u044c\u0441\u044f \u0441 \u043d\u0430\u0448\u0438\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c Emby Connect \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 {0}. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438\u043c\u0435\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438 \u0447\u0442\u043e \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u044b \u0432 \u0431\u0440\u0430\u043d\u0434\u043c\u0430\u0443\u044d\u0440\u0435 \u0438\u043b\u0438 \u041f\u041e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443 \u0432\u0430\u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e.", + "StopRecording": "\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c", + "HeaderStopRecording": "\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u043f\u0438\u0441\u0438", + "ManageRecording": "\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c\u044e", + "LabelDropImageHere": "\u041f\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u0435 \u0440\u0438\u0441\u0443\u043d\u043e\u043a \u0441\u044e\u0434\u0430 \u0438\u043b\u0438 \u0449\u0451\u043b\u043a\u043d\u0438\u0442\u0435 \u0434\u043b\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438", + "MessageFileReadError": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u043d\u0438\u0438 \u0444\u0430\u0439\u043b\u0430. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.", + "Browse": "\u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f", + "HeaderUploadImage": "\u0412\u044b\u043a\u043b\u0430\u0434\u043a\u0430 \u0440\u0438\u0441\u0443\u043d\u043a\u0430", + "HeaderAddUpdateImage": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\/\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0438\u0441\u0443\u043d\u043a\u0430", + "LabelImageType": "\u0422\u0438\u043f \u0440\u0438\u0441\u0443\u043d\u043a\u0430:", + "Upload": "\u0412\u044b\u043a\u043b\u0430\u0434\u043a\u0430", + "Primary": "\u0413\u043e\u043b\u043e\u0432\u043d\u043e\u0439", + "Art": "\u0412\u0438\u043d\u044c\u0435\u0442\u043a\u0430", + "Backdrop": "\u0417\u0430\u0434\u043d\u0438\u043a", + "Banner": "\u0411\u0430\u043d\u043d\u0435\u0440", + "Box": "\u041a\u043e\u0440\u043e\u0431\u043a\u0430", + "BoxRear": "\u0421\u043f\u0438\u043d\u043a\u0430 \u043a\u043e\u0440\u043e\u0431\u043a\u0438", + "Disc": "\u0414\u0438\u0441\u043a", + "Logo": "\u041b\u043e\u0433\u043e\u0442\u0438\u043f", + "Menu": "\u041c\u0435\u043d\u044e", + "Screenshot": "\u0421\u043d\u0438\u043c\u043e\u043a \u044d\u043a\u0440\u0430\u043d\u0430", + "Thumb": "\u0411\u0435\u0433\u0443\u043d\u043e\u043a", + "ValueSeconds": "{0} \u0441\u0435\u043a", + "HeaderAudioSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0430\u0443\u0434\u0438\u043e", + "LabelAudioLanguagePreference": "\u0412\u044b\u0431\u043e\u0440 \u044f\u0437\u044b\u043a\u0430 \u0430\u0443\u0434\u0438\u043e:", + "LabelPlayDefaultAudioTrack": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u0430\u0443\u0434\u0438\u043e\u0434\u043e\u0440\u043e\u0436\u043a\u0443 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u044f\u0437\u044b\u043a\u0430", + "HeaderVideoQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0438\u0434\u0435\u043e", + "CinemaModeConfigurationHelp": "\u0420\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0437\u0430\u043b\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0432\u0430\u043c \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0433\u043e \u0437\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043b\u0430 \u0441 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u0430\u043c\u0438 \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0430\u043c\u0438 \u043f\u0435\u0440\u0435\u0434 \u0444\u0438\u043b\u044c\u043c\u043e\u043c.", + "EnableNextVideoInfoOverlay": "\u0412\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043e \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0432\u0438\u0434\u0435\u043e", + "EnableNextVideoInfoOverlayHelp": "\u0412 \u043a\u043e\u043d\u0446\u0435 \u0432\u0438\u0434\u0435\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0432\u0438\u0434\u0435\u043e \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442\u0435.", + "PlayNextEpisodeAutomatically": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u044d\u043f\u0438\u0437\u043e\u0434 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438", + "LabelMaxChromecastBitrate": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438 Chromecast:", + "LabelSkipBackLength": "\u0412\u0440\u0435\u043c\u044f \u043e\u0442\u043c\u043e\u0442\u043a\u0438:", + "LabelSkipForwardLength": "\u0412\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u043c\u043e\u0442\u043a\u0438:", + "EnableCinemaMode": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0437\u0430\u043b\u0430", + "LabelInternetQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435:", + "HeaderMusicQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043c\u0443\u0437\u044b\u043a\u0438", + "LabelHomeNetworkQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0432 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u0441\u0435\u0442\u0438:", + "HeaderLatestMedia": "\u041d\u043e\u0432\u0435\u0439\u0448\u0438\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435", + "HeaderRestartingEmbyServer": "Emby Server \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f", + "RestartPleaseWaitMessage": "\u041f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435, \u043f\u043e\u043a\u0430 Emby Server \u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u0441\u044f \u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043d\u044f\u0442\u044c \u043c\u0438\u043d\u0443\u0442\u0443 \u0438\u043b\u0438 \u0434\u0432\u0435.", + "PlayNext": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435", + "AllowSeasonalThemes": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0441\u0435\u0437\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u043c\u044b", + "AllowSeasonalThemesHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0441\u0435\u0437\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u043c\u044b \u0431\u0443\u0434\u0443\u0442 \u0432\u0440\u0435\u043c\u044f \u043e\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u0432\u0430\u0448\u0443 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0442\u0435\u043c\u044b.", + "AutoBasedOnLanguageSetting": "\u0410\u0432\u0442\u043e (\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u044f\u0437\u044b\u043a\u0430)", + "LabelDateTimeLocale": "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043c\u044f:", + "DirectorValue": "\u0420\u0435\u0436\u0438\u0441\u0441\u0451\u0440: {0}", + "DirectorsValue": "\u0420\u0435\u0436\u0438\u0441\u0441\u0451\u0440\u044b: {0}", + "GenreValue": "\u0416\u0430\u043d\u0440: {0}", + "GenresValue": "\u0416\u0430\u043d\u0440\u044b: {0}", + "LinksValue": "\u0421\u0441\u044b\u043b\u043a\u0438: {0}", + "TagsValue": "\u0422\u0435\u0433\u0438: {0}", + "LabelAudio": "\u0410\u0443\u0434\u0438\u043e:", + "LabelVideo": "\u0412\u0438\u0434\u0435\u043e:", + "LabelSubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044b:", + "Off": "\u0412\u044b\u043a\u043b", + "ShowTitle": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438", + "ShowYear": "\u0413\u043e\u0434 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438", + "Filters": "\u0424\u0438\u043b\u044c\u0442\u0440\u044b", + "Unplayed": "\u041d\u0435\u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0451\u043d\u043d\u043e\u0435", + "LabelTVHomeScreen": "\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043f\u0440\u0438 \u0422\u0412-\u0440\u0435\u0436\u0438\u043c\u0435", + "Horizontal": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e", + "Vertical": "\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e", + "GroupBySeries": "\u0413\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0430\u043c", + "HeaderVideoType": "\u0422\u0438\u043f \u0432\u0438\u0434\u0435\u043e", + "HeaderSeriesStatus": "\u0421\u0442\u0430\u0442\u0443\u0441 \u0441\u0435\u0440\u0438\u0430\u043b\u0430", + "Features": "\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b", + "Trailers": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u044b", + "Extras": "\u0414\u043e\u043f\u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b", + "ThemeSongs": "\u0422\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043c\u0435\u043b\u043e\u0434\u0438\u0438", + "ThemeVideos": "\u0422\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0432\u0438\u0434\u0435\u043e", + "HeaderFavoriteMovies": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0444\u0438\u043b\u044c\u043c\u044b", + "HeaderFavoriteShows": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438", + "HeaderFavoriteEpisodes": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b", + "HeaderFavoriteVideos": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e", + "HeaderFavoriteGames": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0438\u0433\u0440\u044b", + "HeaderFavoriteArtists": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438", + "HeaderFavoriteAlbums": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0430\u043b\u044c\u0431\u043e\u043c\u044b", + "HeaderFavoriteSongs": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438", + "Ascending": "\u041f\u043e \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430\u043d\u0438\u044e", + "Descending": "\u041f\u043e \u0443\u0431\u044b\u0432\u0430\u043d\u0438\u044e", + "ColorPrimaries": "\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0446\u0432\u0435\u0442\u0430", + "ColorSpace": "\u0426\u0432\u0435\u0442\u043e\u0432\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e", + "ColorTransfer": "\u0426\u0432\u0435\u0442\u043e\u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430", + "VideoRange": "\u0414\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u0432\u0438\u0434\u0435\u043e", + "SeriesDisplayOrderHelp": "\u0423\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u043e\u0432 \u043f\u043e \u0434\u0430\u0442\u0435 \u044d\u0444\u0438\u0440\u0430, \u043f\u043e\u0440\u044f\u0434\u043a\u0443 \u043d\u0430 DVD \u0438\u043b\u0438 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e\u0439 \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438.", + "PlaybackSettingsIntro": "\u0427\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0435\u043e, \u0437\u0430\u0442\u0435\u043c \u0449\u0435\u043b\u043a\u043d\u0438\u0442\u0435 \u0437\u043d\u0430\u0447\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u043f\u0440\u0430\u0432\u043e\u0439 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.", + "SubtitleSettingsIntro": "\u0427\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0432\u0438\u0434 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 \u0438 \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0435\u043e, \u0437\u0430\u0442\u0435\u043c \u0449\u0435\u043b\u043a\u043d\u0438\u0442\u0435 \u0437\u043d\u0430\u0447\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u043f\u0440\u0430\u0432\u043e\u0439 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/sk.json b/src/bower_components/emby-webcomponents/strings/sk.json index 8004ee2e93..57e36f6a51 100644 --- a/src/bower_components/emby-webcomponents/strings/sk.json +++ b/src/bower_components/emby-webcomponents/strings/sk.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Prijať", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Herec", - "Add": "Pridať", - "AddToCollection": "Pridať do zbierky", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Pokročilé", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albumy", - "All": "Všetko", - "AllChannels": "Všetky kanály", - "AllComplexFormats": "Všetky komplexné formáty (ASS, SSA, VOBSUB, PGS, SUB/IDX, a pod.)", - "AllEpisodes": "Všetky epizódy", - "AllLanguages": "Všetky jazyky", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Vždy zobraziť titulky", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Akýkoľvek jazyk", - "Anytime": "Anytime", - "AroundTime": "Okolo {0}", - "Art": "Art", - "Artists": "Umelci", - "AsManyAsPossible": "Najviac ako je možné", - "Ascending": "Vzostupne", - "AspectRatio": "Pomer strán", - "AttemptingWakeServer": "Pokúšam sa zobudiť server. Prosím počkajte...", - "AttributeNew": "Nové", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio kanály nie sú podporované", - "AudioCodecNotSupported": "Audio kodek nie je podporovaný", - "AudioProfileNotSupported": "Audio profil nie je podporovaný", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Automaticky (na základe nastavenia jazyka)", - "AutomaticallyConvertNewContent": "Automaticky konvertovať nový obsah", - "AutomaticallyConvertNewContentHelp": "Nový obsah pridaný do tohto priečinka bude automaticky skonvertovaný.", - "AutomaticallySyncNewContent": "Automaticky sťahovať nový obsah", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Pozadie", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Miesto narodenia", - "Books": "Knihy", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Zrušiť", - "ButtonGotIt": "Rozumiem", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Prehrať jednu minútu", - "ButtonRestart": "Reštartovať", - "ButtonRestorePreviousPurchase": "Obnoviť nákup", - "ButtonTryAgain": "Skúste znova", - "ButtonUnlockPrice": "Odomknúť {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Zrušiť sťahovanie", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Kategórie", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Zbierky", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Farebný priestor", - "ColorTransfer": "Color transfer", - "CommunityRating": "Hodnotenie komunity", - "Composer": "Skladateľ", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Zmazať obrázok?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Potvrdiť zmazanie", - "ConfirmEndPlayerSession": "Chcete vypnúť Jellyfin na {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Pripojiť", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Kontajner nie je podporovaný", - "Continue": "Pokračovať", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Pokračovať v pozeraní", - "Continuing": "Continuing", - "Convert": "Konvertovať", - "ConvertItemLimitHelp": "Voliteľné. Nastaviť limit položiek, ktoré budú konvertované.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Krajiny", - "CriticRating": "Hodnotenie kritikov", - "DateAdded": "Dátum pridania", - "DatePlayed": "Dátum prehrania", - "Days": "Dni", - "Default": "Default", - "DefaultErrorMessage": "Pri spracúvaní požiadavky došlo k chybe. Skúste prosím neskôr znova.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Zmazať", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Zostupne", - "Desktop": "Stolný počítač", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Režisér", - "DirectorValue": "Režisér: {0}", - "DirectorsValue": "Režiséri: {0}", - "Disc": "Disk", - "Disconnect": "Odpojiť", - "Dislike": "Nepáči sa mi to", - "Display": "Display", - "DisplayInMyMedia": "Zobraziť na domácej obrazovke", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Zobraziť chýbajúce epizódy v rámci sezóny.", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Nenahrávať", - "Down": "Dole", - "Download": "Stiahnuť", - "DownloadItemLimitHelp": "Voliteľné. Nastaviť limit položiek, ktoré budú stiahnuté.", - "Downloaded": "Stiahnuté", - "Downloading": "Sťahuje sa", - "DownloadingDots": "Sťahuje sa…", - "Downloads": "Sťahovania", - "DownloadsValue": "{0} stiahnutí", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Upraviť", - "EditImages": "Upraviť obrázky", - "EditMetadata": "Upraviť metadáta", - "EditSubtitles": "Upraviť titulky", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Povoliť externé video prehrávače", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Končí o {0}", - "Episodes": "Epizódy", - "Error": "Chyba", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Veľmi veľké", - "Extras": "Extras", - "Favorite": "Obľúbené", - "Favorites": "Obľúbené", - "FeatureRequiresJellyfinPremiere": "Táto funkcia vyžaduje aktívne predplatné Jellyfin Premiere.", - "Features": "Features", - "File": "Súbor", - "Fill": "Vyplniť", - "Filters": "Filtre", - "Folders": "Folders", - "FormatValue": "Formát: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Piatok", - "GenreValue": "Žáner: {0}", - "Genres": "Žánre", - "GenresValue": "Žánre: {0}", - "GroupBySeries": "Zoskupiť podľa série", - "GroupVersions": "Group versions", - "GuestStar": "Hosťujúca hviezda", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Sprievodca", - "HDPrograms": "HD programy", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Pridať do zbierky", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Pridať/nahrať obrázok", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio knihy", - "HeaderAudioSettings": "Nastavenia zvuku", - "HeaderBecomeProjectSupporter": "Získať Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Výhody Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Pokračovať v počúvaní", - "HeaderContinueWatching": "Pokračovať v pozeraní", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Prispôsobiť domovskú obrazovku", - "HeaderDeleteItem": "Zmazať položku", - "HeaderDeleteItems": "Zmazať položky", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Nastavenia sťahovania", - "HeaderEditImages": "Upraviť obrázky", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Obľúbené albumy", - "HeaderFavoriteArtists": "Obľúbení umelci", - "HeaderFavoriteCollections": "Obľúbené zbierky", - "HeaderFavoriteEpisodes": "Obľúbené epizódy", - "HeaderFavoriteGames": "Obľúbené hry", - "HeaderFavoriteMovies": "Obľúbené filmy", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Obľúbené skladby", - "HeaderFavoriteVideos": "Obľúbené videá", - "HeaderFreeApps": "Jellyfin Apps zdarma", - "HeaderHomeScreen": "Domáca obrazovka", - "HeaderIdentifyItemHelp": "Zadajte jedno alebo viacero kritérií. Odstránenie kritéria zvýši počet výsledkov.", - "HeaderInvitationSent": "Pozvánka odoslaná", - "HeaderJellyfinAccountAdded": "Jellyfin účet pridaný", - "HeaderJellyfinAccountRemoved": "Jellyfin účet odstránený", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Najnovšie od {0}", - "HeaderLatestMedia": "Najnovšie médiá", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Priečinky knižnice", - "HeaderLibraryOrder": "Poradie knižnice", - "HeaderMetadataSettings": "Nastavenia metadát", - "HeaderMusicQuality": "Kvalita hudby", - "HeaderMyDevice": "Moje zariadenie", - "HeaderMyDownloads": "Moje sťahovania", - "HeaderMyMedia": "Moje média", - "HeaderMyMediaSmall": "Moje médiá (malé)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Ďalšia epizóda sa spustí o {0}", - "HeaderNextUp": "Nasleduje", - "HeaderNextVideoPlayingInValue": "Ďalšie video sa spustí o {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Albumy fotografií", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Chyba prehrávania", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Ďiaľkové ovládanie", - "HeaderRestartingJellyfinServer": "Jellyfin Server sa reštartuje", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} sekúnd", - "HeaderSelectDate": "Vyberte dátum", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Začať teraz", - "HeaderStopRecording": "Zastaviť nahrávanie", - "HeaderSubtitleAppearance": "Vzhľad titulkov", - "HeaderSubtitleSettings": "Nastavenia titulkov", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Nahrať obrázok", - "HeaderVideoQuality": "Kvalita videa", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Čakám na WiFi", - "HeaderWakeServer": "Zobudiť server", - "HeaderYouSaid": "You Said...", - "Help": "Pomoc", - "Hide": "Skryť", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Domov", - "Horizontal": "Horizontálne", - "HowDidYouPay": "Ako ste platili?", - "IHaveJellyfinPremiere": "Už mám Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identifikovať", - "Images": "Obrázky", - "ImdbRating": "IMDb hodnotenie", - "InstallingPackage": "Inštalujem {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} položiek", - "Items": "Položky", - "KeepDownload": "Keep download", - "KeepOnDevice": "Ponechať na zariadení", - "Kids": "Detské", - "Label3DFormat": "3D formát:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Umelci:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Uprednostňovaný jazyk zvuku:", - "LabelBirthDate": "Dátum narodenia:", - "LabelBirthYear": "Rok narodenia:", - "LabelBitrateMbps": "Dátový tok (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Kanály:", - "LabelCollection": "Zbierka:", - "LabelCommunityRating": "Hodnotenie komunity:", - "LabelContentType": "Typ obsahu:", - "LabelConvertTo": "Konvertovať do:", - "LabelCountry": "Krajina:", - "LabelCriticRating": "Hodnotenie kritikov:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Dátum pridania:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Dátum úmrtia:", - "LabelDefaultScreen": "Predvolená obrazovka:", - "LabelDiscNumber": "Číslo disku:", - "LabelDisplayLanguage": "Jazyk rozhrania:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Poradie zobrazenia:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mailová adresa:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Číslo epizódy:", - "LabelFont": "Písmo:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Sekcia domácej obrazovky {0}:", - "LabelImageType": "Typ obrázku:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Ponechať:", - "LabelKeepUpTo": "Ponechať najviac:", - "LabelLanguage": "Jazyk:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Maximálny dátový tok pre Chromecast:", - "LabelMetadataDownloadLanguage": "Preferovaný jazyk:", - "LabelName": "Meno:", - "LabelNumber": "Číslo:", - "LabelOriginalAspectRatio": "Pôvodný pomer strán:", - "LabelOriginalTitle": "Pôvodný názov:", - "LabelOverview": "Prehľad:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Rodičovské hodnotenie", - "LabelPath": "Cesta:", - "LabelPersonRole": "Úloha:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Miesto narodenia:", - "LabelPlayDefaultAudioTrack": "Prehrať predvolenú zvukovú stopu bez ohľadu na jazyk", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferovaný jazyk titulkov:", - "LabelProfile": "Profil:", - "LabelQuality": "Kvalita:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Dátum vydania:", - "LabelRuntimeMinutes": "Dĺžka (minúty):", - "LabelScreensaver": "Šetrič obrazokvy:", - "LabelSeasonNumber": "Číslo sezóny:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Krátky prehľad:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Dĺžka skoku dozadu:", - "LabelSkipForwardLength": "Dĺžka skoku dopredu:", - "LabelSortBy": "Zoradiť podľa:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Zvukové efekty:", - "LabelSource": "Zdroj:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Titulky:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Farba pozadia textu:", - "LabelTextColor": "Farba textu:", - "LabelTextSize": "Veľkosť textu:", - "LabelTheme": "Theme:", - "LabelTitle": "Názov:", - "LabelTrackNumber": "Číslo stopy:", - "LabelType": "Typ:", - "LabelVersion": "Verzia:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Farba pozadia textu:", - "LabelYear": "Rok:", - "Large": "Veľké", - "LatestFromLibrary": "Najnovšie {0}", - "LearnHowYouCanContribute": "Zistite ako môžete prispieť.", - "LearnMore": "Zistiť viac", - "Like": "Páči sa mi to", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Naživo", - "LiveBroadcasts": "Živé vysielania", - "LiveTV": "Živý TV prenos", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Živá TV vyžaduje aktívne predplatné Jellyfin Premiere.", - "Logo": "Logo", - "ManageRecording": "Spravovať nahrávanie", - "MarkPlayed": "Označiť ako prehrané", - "MarkUnplayed": "Označiť ako neprehrané", - "MarkWatched": "Označiť ako prehrané", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Stredné", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Ste si istý, že chcete zmazať súbor s titulkami?", - "MessageConfirmRecordingCancellation": "Zrušiť nahrávanie?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Položka uložená.", - "MessageItemsAdded": "Položky pridané.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minút po", - "MinutesBefore": "minút pred", - "Mobile": "Mobil / Tablet", - "Monday": "Pondelok", - "More": "Viac", - "MoveLeft": "Posunúť vľavo", - "MoveRight": "Posunúť vpravo", - "Movies": "Filmy", - "MySubtitles": "Moje titulky", - "Name": "Meno", - "NewCollection": "Nová zbierka", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Príklad: Kolekcia Star Wars", - "NewEpisodes": "Nové epizódy", - "NewEpisodesOnly": "Iba nové epizódy", - "News": "Správy", - "Next": "Ďalšie", - "No": "Nie", - "NoItemsFound": "Žiadne výsledky.", - "NoSubtitleSearchResultsFound": "Žiadne výsledky.", - "NoSubtitles": "Žiadne titulky", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "Žiadne", - "Normal": "Normálne", - "Off": "Off", - "OneChannel": "Jeden kanál", - "OnlyForcedSubtitles": "Iba vynútené titulky", - "OnlyForcedSubtitlesHelp": "Budú zobrazené iba titulky označené ako vynútené.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Otvoriť", - "OptionNew": "Nové...", - "Original": "Originál", - "OriginalAirDateValue": "Pôvodný dátum vysielania: {0}", - "Overview": "Prehľad", - "PackageInstallCancelled": "{0} inštalácia zrušená.", - "PackageInstallCompleted": "{0} inštalácia dokončená.", - "PackageInstallFailed": "{0} inštalácia zlyhala.", - "ParentalRating": "Parental Rating", - "People": "Ľudia", - "PerfectMatch": "Perfektná zhoda", - "Photos": "Fotky", - "PlaceFavoriteChannelsAtBeginning": "Umiestniť obľúbené kanály na začiatok", - "Play": "Prehrať", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Počet prehraní", - "PlayFromBeginning": "Prehrať od začiatku", - "PlayNext": "Prehrať ďalšie", - "PlayNextEpisodeAutomatically": "Automaticky prehrať ďalšiu epizódu", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Prehrané", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Zadajte meno alebo externé ID prosím.", - "PleaseRestartServerName": "Prosím reštartujte Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Vyberte prosím aspoň dve položky.", - "Premiere": "Premiéra", - "Premieres": "Premiéry", - "Previous": "Predchádzajúce", - "Primary": "Primary", - "PrivacyPolicy": "Zásady ochrany osobných údajov", - "Producer": "Producent", - "ProductionLocations": "Miesta produkcie", - "Programs": "Programy", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Kvalita", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Nedávno pozreté", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Nahrávanie zrušené.", - "RecordingScheduled": "Plán nahrávania.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Obnoviť", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Obnoviť metadáta", - "RefreshQueued": "Refresh queued.", - "Reject": "Odmietnuť", - "ReleaseDate": "Dátum vydania", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Odobrať zo zbierky", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Odstraňuje sa zo zariadenia", - "Repeat": "Opakovať", - "RepeatAll": "Opakovať všetko", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Opakovať jedno", - "ReplaceAllMetadata": "Nahradiť všetky metadáta", - "ReplaceExistingImages": "Nahradiť existujúce obrázky", - "RestartPleaseWaitMessage": "Počkajte prosím kým sa Jellyfin Server vypne a znova naštartuje. Môže to trvať minútu alebo dve.", - "ResumeAt": "Pokračovať od {0}", - "Retry": "Skúsiť znova", - "RunAtStartup": "Spustiť pri štarte", - "Runtime": "Runtime", - "Saturday": "Sobota", - "Save": "Uložiť", - "ScanForNewAndUpdatedFiles": "Hľadať nové a aktualizované súbory", - "Schedule": "Schedule", - "Screenshot": "Snímka obrazovky", - "Screenshots": "Snímky obrazovky", - "Search": "Hľadať", - "SearchForCollectionInternetMetadata": "Vyhľadať metadáta a obrázky na Internete.", - "SearchForMissingMetadata": "Hľadať chýbajúce metadáta", - "SearchForSubtitles": "Hľadať titulky", - "SearchResults": "Výsledky vyhľadávania", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Nastavenia série", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} sa reštartuje.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} sa vypína.", - "ServerUpdateNeeded": "Tento Jellyfin server treba aktualizovať. Najnovšiu verziu nájdete na {0}", - "Settings": "Nastavenia", - "SettingsSaved": "Nastavenia uložené.", - "Share": "Zdieľať", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Zobraz rok", - "Shows": "Seriály", - "Shuffle": "Zamiešať", - "SkipEpisodesAlreadyInMyLibrary": "Nenahrávať epizódy, ktoré už sú v mojej knižnici", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Malé", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Skladby", - "Sort": "Zoradiť", - "SortByValue": "Zoradiť podľa {0}", - "SortChannelsBy": "Zoradiť kanály podľa:", - "SortName": "Sort name", - "Sports": "Športy", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Zastaviť nahrávanie", - "Studios": "Štúdiá", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Formát titulkov nie je podporovaný", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Titulky", - "Suggestions": "Návrhy", - "Sunday": "Nedeľa", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Zrušené", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Odstránené zo zariadenia", - "SyncJobItemStatusSynced": "Stiahnuté", - "SyncJobItemStatusSyncedMarkForRemoval": "Odstraňuje sa zo zariadenia", - "SyncJobItemStatusTransferring": "Prenáša sa", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Podmienky použitia", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Štvrtok", - "TrackCount": "{0} stôp", - "Trailer": "Ukážka", - "Trailers": "Ukážky", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Utorok", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Neprehrané", - "Unrated": "Nehodnotené", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Hore", - "Upload": "Nahrať", - "ValueAlbumCount": "{0} albumov", - "ValueDiscNumber": "Disk {0}", - "ValueEpisodeCount": "{0} epizód", - "ValueGameCount": "{0} hier", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} filmov", - "ValueMusicVideoCount": "{0} hudobných videí", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 epizóda", - "ValueOneGame": "1 hra", - "ValueOneItem": "1 položka", - "ValueOneMovie": "1 film", - "ValueOneMusicVideo": "1 hudobné video", - "ValueOneSeries": "1 séria", - "ValueOneSong": "1 skladba", - "ValueSeconds": "{0} sekúnd", - "ValueSeriesCount": "{0} sérií", - "ValueSongCount": "{0} skladieb", - "ValueSpecialEpisodeName": "Špeciál - {0}", - "Vertical": "Vertikálne", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video kodek nie je podporovaný", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profil nie je podporovaný", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Nepodporované rozlíšenie videa", - "ViewAlbum": "Zobraziť album", - "ViewArtist": "Zobraziť umelca", - "VoiceInput": "Hlasový vstup", - "WakeServer": "Zobudiť server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Vyšlo to!", - "Watched": "Watched", - "Wednesday": "Streda", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Áno" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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": "\u0160peci\u00e1l - {0}", + "Share": "Zdie\u013ea\u0165", + "Add": "Prida\u0165", + "ServerUpdateNeeded": "Tento Emby server treba aktualizova\u0165. Najnov\u0161iu verziu n\u00e1jdete na {0}", + "LiveTvRequiresUnlock": "\u017div\u00e1 TV vy\u017eaduje akt\u00edvne predplatn\u00e9 Emby Premiere.", + "AttributeNew": "Nov\u00e9", + "Premiere": "Premi\u00e9ra", + "Live": "Na\u017eivo", + "Repeat": "Opakova\u0165", + "TrackCount": "{0} st\u00f4p", + "ItemCount": "{0} polo\u017eiek", + "OriginalAirDateValue": "P\u00f4vodn\u00fd d\u00e1tum vysielania: {0}", + "EndsAtValue": "Kon\u010d\u00ed o {0}", + "HeaderSelectDate": "Vyberte d\u00e1tum", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Prehran\u00e9", + "ButtonOk": "Ok", + "ButtonCancel": "Zru\u0161i\u0165", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Rozumiem", + "ButtonRestart": "Re\u0161tartova\u0165", + "RecordingCancelled": "Nahr\u00e1vanie zru\u0161en\u00e9.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Pl\u00e1n nahr\u00e1vania.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Zobudi\u0165 server", + "HeaderWakeServer": "Zobudi\u0165 server", + "AttemptingWakeServer": "Pok\u00fa\u0161am sa zobudi\u0165 server. Pros\u00edm po\u010dkajte...", + "WakeServerSuccess": "Vy\u0161lo to!", + "HeaderCustomizeHomeScreen": "Prisp\u00f4sobi\u0165 domovsk\u00fa obrazovku", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Nede\u013ea", + "Monday": "Pondelok", + "Tuesday": "Utorok", + "Wednesday": "Streda", + "Thursday": "\u0160tvrtok", + "Friday": "Piatok", + "Saturday": "Sobota", + "Days": "Dni", + "SortByValue": "Zoradi\u0165 pod\u013ea {0}", + "LabelSortBy": "Zoradi\u0165 pod\u013ea:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Albumy fotografi\u00ed", + "Photos": "Fotky", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "S\u0165ahovania", + "HeaderMyDownloads": "Moje s\u0165ahovania", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", + "HeaderFreeApps": "Emby Apps zdarma", + "FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.", + "HeaderBecomeProjectSupporter": "Z\u00edska\u0165 Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "LabelEmailAddress": "E-mailov\u00e1 adresa:", + "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Emby Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Emby server settings.", + "FeatureRequiresEmbyPremiere": "T\u00e1to funkcia vy\u017eaduje akt\u00edvne predplatn\u00e9 Emby Premiere.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Ulo\u017ei\u0165", + "Edit": "Upravi\u0165", + "Download": "Stiahnu\u0165", + "Downloaded": "Stiahnut\u00e9", + "Downloading": "S\u0165ahuje sa", + "Advanced": "Pokro\u010dil\u00e9", + "Delete": "Zmaza\u0165", + "HeaderDeleteItem": "Zmaza\u0165 polo\u017eku", + "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", + "Refresh": "Obnovi\u0165", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Prida\u0165 do zbierky", + "HeaderAddToCollection": "Prida\u0165 do zbierky", + "NewCollection": "Nov\u00e1 zbierka", + "LabelCollection": "Zbierka:", + "Help": "Pomoc", + "LabelDisplayMode": "Display mode:", + "Desktop": "Stoln\u00fd po\u010d\u00edta\u010d", + "Mobile": "Mobil \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Jazyk rozhrania:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Zistite ako m\u00f4\u017eete prispie\u0165.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Vyh\u013eada\u0165 metad\u00e1ta a obr\u00e1zky na Internete.", + "DisplayMissingEpisodesWithinSeasons": "Zobrazi\u0165 ch\u00fdbaj\u00face epiz\u00f3dy v r\u00e1mci sez\u00f3ny.", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Spusti\u0165 pri \u0161tarte", + "LabelScreensaver": "\u0160etri\u010d obrazokvy:", + "LabelSoundEffects": "Zvukov\u00e9 efekty:", + "LabelSkin": "Skin:", + "LabelName": "Meno:", + "NewCollectionNameExample": "Pr\u00edklad: Kolekcia Star Wars", + "MessageItemsAdded": "Polo\u017eky pridan\u00e9.", + "OptionNew": "Nov\u00e9...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Titulky", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "H\u013eada\u0165 titulky", + "LabelLanguage": "Jazyk:", + "Search": "H\u013eada\u0165", + "NoSubtitleSearchResultsFound": "\u017diadne v\u00fdsledky.", + "File": "S\u00fabor", + "MessageAreYouSureDeleteSubtitles": "Ste si ist\u00fd, \u017ee chcete zmaza\u0165 s\u00fabor s titulkami?", + "ConfirmDeletion": "Potvrdi\u0165 zmazanie", + "MySubtitles": "Moje titulky", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Upravi\u0165 titulky", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Obnovi\u0165 metad\u00e1ta", + "ReplaceExistingImages": "Nahradi\u0165 existuj\u00face obr\u00e1zky", + "ReplaceAllMetadata": "Nahradi\u0165 v\u0161etky metad\u00e1ta", + "SearchForMissingMetadata": "H\u013eada\u0165 ch\u00fdbaj\u00face metad\u00e1ta", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "\u017diadne v\u00fdsledky.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Sk\u00faste znova", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disk {0}", + "Unrated": "Nehodnoten\u00e9", + "Favorite": "Ob\u013e\u00faben\u00e9", + "Like": "P\u00e1\u010di sa mi to", + "Dislike": "Nep\u00e1\u010di sa mi to", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Otvori\u0165", + "Play": "Prehra\u0165", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Zamie\u0161a\u0165", + "Identify": "Identifikova\u0165", + "EditImages": "Upravi\u0165 obr\u00e1zky", + "EditMetadata": "Upravi\u0165 metad\u00e1ta", + "Convert": "Konvertova\u0165", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "Zobrazi\u0165 album", + "ViewArtist": "Zobrazi\u0165 umelca", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Prehra\u0165 od za\u010diatku", + "ResumeAt": "Pokra\u010dova\u0165 od {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Odobra\u0165 zo zbierky", + "Sort": "Zoradi\u0165", + "Trailer": "Uk\u00e1\u017eka", + "MarkPlayed": "Ozna\u010di\u0165 ako prehran\u00e9", + "MarkUnplayed": "Ozna\u010di\u0165 ako neprehran\u00e9", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Vyberte pros\u00edm aspo\u0148 dve polo\u017eky.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Zru\u0161i\u0165 nahr\u00e1vanie?", + "Error": "Chyba", + "VoiceInput": "Hlasov\u00fd vstup", + "LabelContentType": "Typ obsahu:", + "LabelPath": "Cesta:", + "Playlists": "Playlists", + "LabelTitle": "N\u00e1zov:", + "LabelOriginalTitle": "P\u00f4vodn\u00fd n\u00e1zov:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "D\u00e1tum pridania:", + "DateAdded": "D\u00e1tum pridania", + "DatePlayed": "D\u00e1tum prehrania", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Umelci:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Umelci", + "ImdbRating": "IMDb hodnotenie", + "CommunityRating": "Hodnotenie komunity", + "LabelCommunityRating": "Hodnotenie komunity:", + "LabelCriticRating": "Hodnotenie kritikov:", + "CriticRating": "Hodnotenie kritikov", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Preh\u013ead:", + "LabelShortOverview": "Kr\u00e1tky preh\u013ead:", + "LabelReleaseDate": "D\u00e1tum vydania:", + "LabelYear": "Rok:", + "LabelPlaceOfBirth": "Miesto narodenia:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "D\u013a\u017eka (min\u00faty):", + "LabelParentalRating": "Rodi\u010dovsk\u00e9 hodnotenie", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "P\u00f4vodn\u00fd pomer str\u00e1n:", + "Label3DFormat": "3D form\u00e1t:", + "FormatValue": "Form\u00e1t: {0}", + "DownloadsValue": "{0} stiahnut\u00ed", + "PerfectMatch": "Perfektn\u00e1 zhoda", + "EnableExternalVideoPlayers": "Povoli\u0165 extern\u00e9 video prehr\u00e1va\u010de", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Poradie zobrazenia:", + "Display": "Display", + "Countries": "Krajiny", + "Genres": "\u017d\u00e1nre", + "Studios": "\u0160t\u00fadi\u00e1", + "Tags": "Tags", + "HeaderMetadataSettings": "Nastavenia metad\u00e1t", + "People": "\u013dudia", + "LabelMetadataDownloadLanguage": "Preferovan\u00fd jazyk:", + "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", + "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", + "LabelCountry": "Krajina:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Rok narodenia:", + "LabelBirthDate": "D\u00e1tum narodenia:", + "LabelDeathDate": "D\u00e1tum \u00famrtia:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "\u010c\u00edslo sez\u00f3ny:", + "LabelEpisodeNumber": "\u010c\u00edslo epiz\u00f3dy:", + "LabelTrackNumber": "\u010c\u00edslo stopy:", + "LabelNumber": "\u010c\u00edslo:", + "LabelDiscNumber": "\u010c\u00edslo disku:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "D\u00e1tum vydania", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Pozadie", + "Images": "Obr\u00e1zky", + "Runtime": "Runtime", + "ProductionLocations": "Miesta produkcie", + "BirthLocation": "Miesto narodenia", + "ParentalRating": "Parental Rating", + "PlayCount": "Po\u010det prehran\u00ed", + "Name": "Meno", + "Overview": "Preh\u013ead", + "LabelType": "Typ:", + "LabelPersonRole": "\u00daloha:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Herec", + "Composer": "Skladate\u013e", + "Director": "Re\u017eis\u00e9r", + "GuestStar": "Hos\u0165uj\u00faca hviezda", + "Producer": "Producent", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "In\u0161talujem {0}", + "PackageInstallCompleted": "{0} in\u0161tal\u00e1cia dokon\u010den\u00e1.", + "PackageInstallFailed": "{0} in\u0161tal\u00e1cia zlyhala.", + "PackageInstallCancelled": "{0} in\u0161tal\u00e1cia zru\u0161en\u00e1.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 polo\u017eka", + "ValueOneSong": "1 skladba", + "ValueSongCount": "{0} skladieb", + "ValueOneMovie": "1 film", + "ValueMovieCount": "{0} filmov", + "ValueOneSeries": "1 s\u00e9ria", + "ValueSeriesCount": "{0} s\u00e9ri\u00ed", + "ValueOneEpisode": "1 epiz\u00f3da", + "ValueEpisodeCount": "{0} epiz\u00f3d", + "ValueOneGame": "1 hra", + "ValueGameCount": "{0} hier", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albumov", + "ValueOneMusicVideo": "1 hudobn\u00e9 video", + "ValueMusicVideoCount": "{0} hudobn\u00fdch vide\u00ed", + "ValueMinutes": "{0} min", + "Albums": "Albumy", + "Songs": "Skladby", + "Books": "Knihy", + "HeaderAudioBooks": "Audio knihy", + "HeaderIdentifyItemHelp": "Zadajte jedno alebo viacero krit\u00e9ri\u00ed. Odstr\u00e1nenie krit\u00e9ria zv\u00fd\u0161i po\u010det v\u00fdsledkov.", + "PleaseEnterNameOrId": "Zadajte meno alebo extern\u00e9 ID pros\u00edm.", + "MessageItemSaved": "Polo\u017eka ulo\u017een\u00e1.", + "SearchResults": "V\u00fdsledky vyh\u013ead\u00e1vania", + "ServerNameIsRestarting": "Emby Server - {0} sa re\u0161tartuje.", + "ServerNameIsShuttingDown": "Emby Server - {0} sa vyp\u00edna.", + "HeaderDeleteItems": "Zmaza\u0165 polo\u017eky", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Pros\u00edm re\u0161tartujte Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Kvalita:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "S\u0165ahuje sa\u2026", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Zisti\u0165 viac", + "LabelProfile": "Profil:", + "LabelBitrateMbps": "D\u00e1tov\u00fd tok (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automaticky s\u0165ahova\u0165 nov\u00fd obsah", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automaticky konvertova\u0165 nov\u00fd obsah", + "AutomaticallyConvertNewContentHelp": "Nov\u00fd obsah pridan\u00fd do tohto prie\u010dinka bude automaticky skonvertovan\u00fd.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Volite\u013en\u00e9. Nastavi\u0165 limit polo\u017eiek, ktor\u00e9 bud\u00fa konvertovan\u00e9.", + "DownloadItemLimitHelp": "Volite\u013en\u00e9. Nastavi\u0165 limit polo\u017eiek, ktor\u00e9 bud\u00fa stiahnut\u00e9.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Sn\u00edmky obrazovky", + "MoveRight": "Posun\u00fa\u0165 vpravo", + "MoveLeft": "Posun\u00fa\u0165 v\u013eavo", + "ConfirmDeleteImage": "Zmaza\u0165 obr\u00e1zok?", + "HeaderEditImages": "Upravi\u0165 obr\u00e1zky", + "Settings": "Nastavenia", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "Nov\u00e9 epiz\u00f3dy", + "Episodes": "Epiz\u00f3dy", + "HDPrograms": "HD programy", + "Programs": "Programy", + "LiveBroadcasts": "\u017div\u00e9 vysielania", + "Premieres": "Premi\u00e9ry", + "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": "Nastavenia s\u00e9rie", + "HeaderRecordingOptions": "Recording Options", + "CancelSeries": "Cancel series", + "DoNotRecord": "Nenahr\u00e1va\u0165", + "HeaderSeriesOptions": "Series Options", + "LabelChannels": "Kan\u00e1ly:", + "ChannelNameOnly": "Channel {0} only", + "Anytime": "Anytime", + "AnyLanguage": "Ak\u00fdko\u013evek jazyk", + "AroundTime": "Okolo {0}", + "All": "V\u0161etko", + "AllChannels": "V\u0161etky kan\u00e1ly", + "LabelRecord": "Record:", + "NewEpisodesOnly": "Iba nov\u00e9 epiz\u00f3dy", + "AllEpisodes": "V\u0161etky epiz\u00f3dy", + "LabelStartWhenPossible": "Start when possible:", + "LabelStopWhenPossible": "Stop when possible:", + "MinutesBefore": "min\u00fat pred", + "MinutesAfter": "min\u00fat po", + "SkipEpisodesAlreadyInMyLibrary": "Nenahr\u00e1va\u0165 epiz\u00f3dy, ktor\u00e9 u\u017e s\u00fa v mojej kni\u017enici", + "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", + "LabelKeepUpTo": "Ponecha\u0165 najviac:", + "AsManyAsPossible": "Najviac ako je mo\u017en\u00e9", + "DefaultErrorMessage": "Pri sprac\u00favan\u00ed po\u017eiadavky do\u0161lo k chybe. Sk\u00faste pros\u00edm nesk\u00f4r znova.", + "LabelKeep:": "Ponecha\u0165:", + "UntilIDelete": "Until I delete", + "UntilSpaceNeeded": "Until space needed", + "Categories": "Kateg\u00f3rie", + "Sports": "\u0160porty", + "News": "Spr\u00e1vy", + "Movies": "Filmy", + "Kids": "Detsk\u00e9", + "EnableColorCodedBackgrounds": "Enable color coded backgrounds", + "SortChannelsBy": "Zoradi\u0165 kan\u00e1ly pod\u013ea:", + "RecentlyWatched": "Ned\u00e1vno pozret\u00e9", + "ChannelNumber": "Channel number", + "HeaderBenefitsEmbyPremiere": "V\u00fdhody Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Emby.", + "HeaderTryPlayback": "Try Playback", + "HowDidYouPay": "Ako ste platili?", + "IHaveEmbyPremiere": "U\u017e m\u00e1m Emby Premiere", + "IPurchasedThisApp": "I purchased this app", + "ButtonRestorePreviousPurchase": "Obnovi\u0165 n\u00e1kup", + "ButtonUnlockWithPurchase": "Unlock with Purchase", + "ButtonUnlockPrice": "Odomkn\u00fa\u0165 {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}", + "HeaderAlreadyPaid": "Already Paid?", + "ButtonPlayOneMinute": "Prehra\u0165 jednu min\u00fatu", + "PlaceFavoriteChannelsAtBeginning": "Umiestni\u0165 ob\u013e\u00faben\u00e9 kan\u00e1ly na za\u010diatok", + "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", + "Items": "Polo\u017eky", + "OneChannel": "Jeden kan\u00e1l", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Odstra\u0148uje sa zo zariadenia", + "KeepOnDevice": "Ponecha\u0165 na zariaden\u00ed", + "CancelDownload": "Zru\u0161i\u0165 s\u0165ahovanie", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Odstra\u0148uje sa zo zariadenia", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Pren\u00e1\u0161a sa", + "SyncJobItemStatusSynced": "Stiahnut\u00e9", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Odstr\u00e1nen\u00e9 zo zariadenia", + "SyncJobItemStatusCancelled": "Zru\u0161en\u00e9", + "Retry": "Sk\u00fasi\u0165 znova", + "HeaderMyDevice": "Moje zariadenie", + "Continue": "Pokra\u010dova\u0165", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "\u010eia\u013ekov\u00e9 ovl\u00e1danie", + "Disconnect": "Odpoji\u0165", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Kvalita", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Pomer str\u00e1n", + "Original": "Origin\u00e1l", + "Fill": "Vyplni\u0165", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Prija\u0165", + "Reject": "Odmietnu\u0165", + "Connect": "Pripoji\u0165", + "HeaderMyMedia": "Moje m\u00e9dia", + "HeaderMyMediaSmall": "Moje m\u00e9di\u00e1 (mal\u00e9)", + "LatestFromLibrary": "Najnov\u0161ie {0}", + "ContinueWatching": "Pokra\u010dova\u0165 v pozeran\u00ed", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Pokra\u010dova\u0165 v pozeran\u00ed", + "HeaderContinueListening": "Pokra\u010dova\u0165 v po\u010d\u00favan\u00ed", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Konvertova\u0165 do:", + "Next": "\u010eal\u0161ie", + "LabelSource": "Zdroj:", + "LabelVersion": "Verzia:", + "AllLanguages": "V\u0161etky jazyky", + "Previous": "Predch\u00e1dzaj\u00face", + "HeaderNextUp": "Nasleduje", + "HeaderLatestFrom": "Najnov\u0161ie od {0}", + "LabelHomeScreenSectionValue": "Sekcia dom\u00e1cej obrazovky {0}:", + "SettingsSaved": "Nastavenia ulo\u017een\u00e9.", + "None": "\u017diadne", + "More": "Viac", + "Up": "Hore", + "Down": "Dole", + "Home": "Domov", + "Favorites": "Ob\u013e\u00faben\u00e9", + "HeaderHomeScreen": "Dom\u00e1ca obrazovka", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Poradie kni\u017enice", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Chyba prehr\u00e1vania", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Sprievodca", + "Suggestions": "N\u00e1vrhy", + "HeaderFavoriteCollections": "Ob\u013e\u00faben\u00e9 zbierky", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Zbierky", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Zobrazi\u0165 na dom\u00e1cej obrazovke", + "Shows": "Seri\u00e1ly", + "HeaderLibraryFolders": "Prie\u010dinky kni\u017enice", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Z\u00e1sady ochrany osobn\u00fdch \u00fadajov", + "TermsOfUse": "Podmienky pou\u017eitia", + "RepeatMode": "Repeat mode", + "RepeatOne": "Opakova\u0165 jedno", + "RepeatAll": "Opakova\u0165 v\u0161etko", + "LabelDefaultScreen": "Predvolen\u00e1 obrazovka:", + "ConfirmEndPlayerSession": "Chcete vypn\u00fa\u0165 Emby na {0}?", + "Yes": "\u00c1no", + "No": "Nie", + "LiveTV": "\u017div\u00fd TV prenos", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Ozna\u010di\u0165 ako prehran\u00e9", + "ScanForNewAndUpdatedFiles": "H\u013eada\u0165 nov\u00e9 a aktualizovan\u00e9 s\u00fabory", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video kodek nie je podporovan\u00fd", + "AudioCodecNotSupported": "Audio kodek nie je podporovan\u00fd", + "SubtitleCodecNotSupported": "Form\u00e1t titulkov nie je podporovan\u00fd", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Kontajner nie je podporovan\u00fd", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio kan\u00e1ly nie s\u00fa podporovan\u00e9", + "VideoResolutionNotSupported": "Nepodporovan\u00e9 rozl\u00ed\u0161enie videa", + "AudioProfileNotSupported": "Audio profil nie je podporovan\u00fd", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby \u00fa\u010det odstr\u00e1nen\u00fd", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Pozv\u00e1nka odoslan\u00e1", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby \u00fa\u010det pridan\u00fd", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "\u017diadne titulky", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Mal\u00e9", + "Smaller": "Smaller", + "Medium": "Stredn\u00e9", + "Large": "Ve\u013ek\u00e9", + "ExtraLarge": "Ve\u013emi ve\u013ek\u00e9", + "OnlyForcedSubtitles": "Iba vyn\u00faten\u00e9 titulky", + "AlwaysPlaySubtitles": "V\u017edy zobrazi\u0165 titulky", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Nastavenia titulkov", + "HeaderSubtitleAppearance": "Vzh\u013ead titulkov", + "OnlyForcedSubtitlesHelp": "Bud\u00fa zobrazen\u00e9 iba titulky ozna\u010den\u00e9 ako vyn\u00faten\u00e9.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferovan\u00fd jazyk titulkov:", + "LabelTextSize": "Ve\u013ekos\u0165 textu:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Farba pozadia textu:", + "LabelWindowBackgroundColor": "Farba pozadia textu:", + "LabelFont": "P\u00edsmo:", + "LabelTextColor": "Farba textu:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Norm\u00e1lne", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "V\u0161etky komplexn\u00e9 form\u00e1ty (ASS, SSA, VOBSUB, PGS, SUB\/IDX, a pod.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "\u010cak\u00e1m na WiFi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Nastavenia s\u0165ahovania", + "Hide": "Skry\u0165", + "HeaderStartNow": "Za\u010da\u0165 teraz", + "HeaderNextVideoPlayingInValue": "\u010eal\u0161ie video sa spust\u00ed o {0}", + "HeaderNextEpisodePlayingInValue": "\u010eal\u0161ia epiz\u00f3da sa spust\u00ed o {0}", + "HeaderSecondsValue": "{0} sek\u00fand", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profil nie je podporovan\u00fd", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Zastavi\u0165 nahr\u00e1vanie", + "HeaderStopRecording": "Zastavi\u0165 nahr\u00e1vanie", + "ManageRecording": "Spravova\u0165 nahr\u00e1vanie", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Nahra\u0165 obr\u00e1zok", + "HeaderAddUpdateImage": "Prida\u0165\/nahra\u0165 obr\u00e1zok", + "LabelImageType": "Typ obr\u00e1zku:", + "Upload": "Nahra\u0165", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disk", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Sn\u00edmka obrazovky", + "Thumb": "Thumb", + "ValueSeconds": "{0} sek\u00fand", + "HeaderAudioSettings": "Nastavenia zvuku", + "LabelAudioLanguagePreference": "Uprednost\u0148ovan\u00fd jazyk zvuku:", + "LabelPlayDefaultAudioTrack": "Prehra\u0165 predvolen\u00fa zvukov\u00fa stopu bez oh\u013eadu na jazyk", + "HeaderVideoQuality": "Kvalita videa", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Automaticky prehra\u0165 \u010fal\u0161iu epiz\u00f3du", + "LabelMaxChromecastBitrate": "Maxim\u00e1lny d\u00e1tov\u00fd tok pre Chromecast:", + "LabelSkipBackLength": "D\u013a\u017eka skoku dozadu:", + "LabelSkipForwardLength": "D\u013a\u017eka skoku dopredu:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Kvalita hudby", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Najnov\u0161ie m\u00e9di\u00e1", + "HeaderRestartingEmbyServer": "Emby Server sa re\u0161tartuje", + "RestartPleaseWaitMessage": "Po\u010dkajte pros\u00edm k\u00fdm sa Emby Server vypne a znova na\u0161tartuje. M\u00f4\u017ee to trva\u0165 min\u00fatu alebo dve.", + "PlayNext": "Prehra\u0165 \u010fal\u0161ie", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Automaticky (na z\u00e1klade nastavenia jazyka)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Re\u017eis\u00e9r: {0}", + "DirectorsValue": "Re\u017eis\u00e9ri: {0}", + "GenreValue": "\u017d\u00e1ner: {0}", + "GenresValue": "\u017d\u00e1nre: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Titulky:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Zobraz rok", + "Filters": "Filtre", + "Unplayed": "Neprehran\u00e9", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizont\u00e1lne", + "Vertical": "Vertik\u00e1lne", + "GroupBySeries": "Zoskupi\u0165 pod\u013ea s\u00e9rie", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Uk\u00e1\u017eky", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Ob\u013e\u00faben\u00e9 filmy", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Ob\u013e\u00faben\u00e9 epiz\u00f3dy", + "HeaderFavoriteVideos": "Ob\u013e\u00faben\u00e9 vide\u00e1", + "HeaderFavoriteGames": "Ob\u013e\u00faben\u00e9 hry", + "HeaderFavoriteArtists": "Ob\u013e\u00faben\u00ed umelci", + "HeaderFavoriteAlbums": "Ob\u013e\u00faben\u00e9 albumy", + "HeaderFavoriteSongs": "Ob\u013e\u00faben\u00e9 skladby", + "Ascending": "Vzostupne", + "Descending": "Zostupne", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Farebn\u00fd priestor", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/sl-si.json b/src/bower_components/emby-webcomponents/strings/sl-si.json index fb0e32900b..d3f180d2ee 100644 --- a/src/bower_components/emby-webcomponents/strings/sl-si.json +++ b/src/bower_components/emby-webcomponents/strings/sl-si.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Cancel", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "Uporaba te funkcionalnosti zahteva aktivno Jellyfin Premiere narocnino.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friday", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Dodaj v Zbirko", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Izvajalci:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Tip vsebine:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Drzava:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Jezik:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Kvaliteta:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Monday", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Saturday", - "Save": "Save", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Nastavitve", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Sunday", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Thursday", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tuesday", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Wednesday", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Cancel", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "Uporaba te funkcionalnosti zahteva aktivno Emby Premiere narocnino.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "Save", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Dodaj v Zbirko", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Jezik:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Tip vsebine:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Izvajalci:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Drzava:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Kvaliteta:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Nastavitve", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/sv.json b/src/bower_components/emby-webcomponents/strings/sv.json index a465d4826d..c3e17dad83 100644 --- a/src/bower_components/emby-webcomponents/strings/sv.json +++ b/src/bower_components/emby-webcomponents/strings/sv.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Acceptera", - "AccessRestrictedTryAgainLater": "Åtkomst är begränsad. Försök igen senare.", - "Actor": "Skådespelare", - "Add": "Lägg till", - "AddToCollection": "Lägg till samling", - "AddToPlayQueue": "Lägg till i spelkö", - "AddToPlaylist": "Lägg till i spellista", - "AddedOnValue": "Tillagd {0}", - "Advanced": "Avancerat", - "AirDate": "Sändningstid", - "Aired": "Sändes", - "Albums": "Album", - "All": "Alla", - "AllChannels": "Alla kanaler", - "AllComplexFormats": "Alla komplexa format (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "Alla avsnitt", - "AllLanguages": "Alla språk", - "AllowSeasonalThemes": "Tillåt automatiska säsongsbaserade teman", - "AllowSeasonalThemesHelp": "Om aktiverat kommer säsongsteman emellanåt kringgå din temainställning.", - "AlwaysPlaySubtitles": "Visa alltid undertexter", - "AlwaysPlaySubtitlesHelp": "Undertexter på det önskade språket kommer att laddas oavsett ljudspårets språk.", - "AnamorphicVideoNotSupported": "Anamorphic video stöds inte", - "AndroidUnlockRestoreHelp": "För att återställa ditt tidigare köp, se till så att du är inloggad på enheten med samma Google (eller Amazon) konto som genomförde köpet. Kolla så att appstore är aktiverat och att det inte är begränsat med barnspärrar samt att det finns en aktiv internetuppkoppling. Du behöver endast göra detta en gång för att återställa ditt tidigare köp.", - "AnyLanguage": "Vilket språk som helst", - "Anytime": "När som helst", - "AroundTime": "Runt {0}", - "Art": "Grafik", - "Artists": "Artister", - "AsManyAsPossible": "Så många som möjligt", - "Ascending": "Ascending", - "AspectRatio": "Bildförhållande", - "AttemptingWakeServer": "Försöker väcka servern. Vänligen vänta....", - "AttributeNew": "Ny", - "AudioBitDepthNotSupported": "Ljudets bitdjup stöds inte", - "AudioBitrateNotSupported": "Ljudbithastigheten stöds inte", - "AudioChannelsNotSupported": "Ljudkanaler stöds inte", - "AudioCodecNotSupported": "Ljud codec stöds inte", - "AudioProfileNotSupported": "Ljudprofil stöds inte", - "AudioSampleRateNotSupported": "Ljudsamplingrate stöds inte", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Automatisk (baserad på språkinställning)", - "AutomaticallyConvertNewContent": "Konvertera nytt innehåll automatiskt", - "AutomaticallyConvertNewContentHelp": "Nytt innehåll till den här mappen kommer automatiskt att konverteras.", - "AutomaticallySyncNewContent": "Ladda ned nytt innehåll automatiskt", - "AutomaticallySyncNewContentHelp": "Nytt innehåll till den här mappen kommer automatiskt att laddas ned till enheten.", - "Backdrop": "Fondbild", - "Backdrops": "Fondbilder", - "Banner": "Banderoll", - "BestFit": "Anpassad", - "BirthLocation": "Födelseort", - "Books": "Böcker", - "Box": "Omslag", - "BoxRear": "Omslag (baksida)", - "Browse": "Bläddra", - "BurnSubtitlesHelp": "Avgör ifall servern ska \"bränna in\" undertexterna under videokonverteringen, beroende på undertextsformatet. Att undvika inbränning av undertexter kommer att förbättra prestandan på servern. Välj Auto för att bränna image-baserade formats (ex. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA undertexter.", - "ButtonCancel": "Avbryt", - "ButtonGotIt": "Ok", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Spela en minut", - "ButtonRestart": "Starta om", - "ButtonRestorePreviousPurchase": "Återställ köp", - "ButtonTryAgain": "Försök igen", - "ButtonUnlockPrice": "Lås upp {0}", - "ButtonUnlockWithPurchase": "Lås upp med köp", - "CancelDownload": "Avbryt nedladdning", - "CancelRecording": "Avbryt inspelning", - "CancelSeries": "Avbryt serie", - "Categories": "Kategorier", - "ChannelNameOnly": "Endast kanal {0}", - "ChannelNumber": "Kanalnummer", - "CinemaModeConfigurationHelp": "Bioläget gör ditt vardagsrum till en biograf genom möjligheten att visa trailers och egna vinjetter innan filmen börjar.", - "CinemaModeFeatureDescription": "Bioläget ger dig en bioupplevelse med trailers och anpassade intros före varje film.", - "CloudSyncFeatureDescription": "Synka din media till molnet för lätttillgängligt backup, arkivering och konvertering.", - "Collections": "Samlingar", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Användaromdöme", - "Composer": "Kompositör", - "ConfigureDateAdded": "Konfigurera hur tillagt datum bestäms i Jellyfin servern under Biblioteksinställningar", - "ConfirmDeleteImage": "Ta bort bild?", - "ConfirmDeleteItem": "Tar du bort det här objeketet så tas det bort från både ditt filsystem och mediabibliotek. Är du säker på att du vill fortsätta?", - "ConfirmDeleteItems": "Tar du bort dessa objekt tas dom också bort ifrån både ditt filsystem och mediabibliotek. Är du säker på att du vill fortsätta?", - "ConfirmDeletion": "Bekräfta radering", - "ConfirmEndPlayerSession": "Vill du stänga ner Jellyfin på {0}?", - "ConfirmRemoveDownload": "Ta bort nedladdning?", - "Connect": "Anslut", - "ContainerBitrateExceedsLimit": "Medians bithastighet överskrider begränsningen", - "ContainerNotSupported": "Kontainern stöds inte", - "Continue": "Fortsätt", - "ContinueInSecondsValue": "Fortsätt om {0} sekunder.", - "ContinueWatching": "Fortsätt titta på", - "Continuing": "Pågående", - "Convert": "Konvertera", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Konvertera endast osedda videos", - "ConvertUnwatchedVideosOnlyHelp": "Endast osedda videos kommer att konverteras.", - "ConvertingDots": "Converting...", - "Countries": "Länder", - "CriticRating": "Kritikerbetyg", - "DateAdded": "Inlagd den", - "DatePlayed": "Senast visad", - "Days": "Dagar", - "Default": "Standard", - "DefaultErrorMessage": "Ett fel uppstd vid begäran. Försök igen senare.", - "DefaultSubtitlesHelp": "Undertexter visas baserat på standardspråk och tvingande undertexter i den inbäddade metadatan. Förvalsspråk kommer väljas när fler val är möjliga.", - "Delete": "Ta bort", - "DeleteMedia": "Ta bort media", - "Depressed": "Nedsänkt", - "Descending": "Descending", - "Desktop": "Skrivbord", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direktuppspelning", - "DirectStreamHelp1": "Innehållet är kompatibelt med enheten vad gäller upplösning och mediatyp (H.264, AC3, etc.) men det är en inkompatibel filkontainer (.mkv, .avi, .wmv etc.). Video-filen kommer att packas om live innan strömningen startar till enheten.", - "DirectStreamHelp2": "Direktströmning av en fil använder väldigt lite resurser av CPU'n utan att bildkvaliten försämras.", - "DirectStreaming": "Direktströmning", - "Director": "Regissör", - "DirectorValue": "Regi: {0}", - "DirectorsValue": "Regi: {0}", - "Disc": "Skiva", - "Disconnect": "Koppla bort", - "Dislike": "Ogilla", - "Display": "Visning", - "DisplayInMyMedia": "Visa på hemskärmen", - "DisplayInOtherHomeScreenSections": "Visa sektioner på hemskärmen som till exempel senast media och fortsätt kolla på", - "DisplayMissingEpisodesWithinSeasons": "Visa saknade avsnitt i säsonger", - "DisplayMissingEpisodesWithinSeasonsHelp": "Detta måste också vara aktiverat för TV-bibliotek på Jellyfin-servern.", - "DisplayModeHelp": "Välj vilken typ av skärm som du kör Jellyfin på.", - "DoNotRecord": "Spela inte in", - "Down": "Ner", - "Download": "Ladda ned", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Nedladdade", - "Downloading": "Laddar ner", - "DownloadingDots": "Laddar ner...", - "Downloads": "Hämtningar", - "DownloadsValue": "Nedladdningar: {0}", - "DropShadow": "Visa skugga", - "DvrFeatureDescription": "Schemalägg individuella LiveTV-inspelningar, serie-inspelningar och mer med Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR kräver en aktiv Jellyfin Premium prenumeration.", - "Edit": "Ändra", - "EditImages": "Ändra bilder", - "EditMetadata": "Redigera metadata", - "EditSubtitles": "Ändra undertexter", - "EnableBackdrops": "Aktivera fondbilder", - "EnableBackdropsHelp": "Om aktiverat visas fondbilder i bakgrunden av vissa sidor vid bläddring i biblioteket.", - "EnableCinemaMode": "Aktivera bioläge", - "EnableColorCodedBackgrounds": "Aktivera färgkodade bakgrundsbilder", - "EnableDisplayMirroring": "Aktivera skärmspegling", - "EnableExternalVideoPlayers": "Aktivera externa videospelare", - "EnableExternalVideoPlayersHelp": "En extern uppspelningsmeny kommer att visas när man startar en videouppspelning.", - "EnableNextVideoInfoOverlay": "Visa info om nästa video under uppspelning", - "EnableNextVideoInfoOverlayHelp": "Vid slutet av en video, visa information om nästföljande video i spellistan.", - "EnableThemeSongs": "Aktivera ledmotiv", - "EnableThemeSongsHelp": "Om aktiverat spelas ledmotiv upp vid bläddring i biblioteket.", - "EnableThemeVideos": "Aktivera tema-videos", - "EnableThemeVideosHelp": "Visar tema-videos i bakgrunden när man bläddrar i biblioteket.", - "Ended": "Avslutad", - "EndsAtValue": "Slutar vid: {0}", - "Episodes": "Avsnitt", - "Error": "Fel", - "ErrorAddingGuestAccount1": "Det gick inte att lägga till Jellyfin Connect-kontot. Har din gäst ett Jellyfin-konto? Dom kan skapa ett på {0}", - "ErrorAddingGuestAccount2": "Om du fortfarande upplever problem, vänligen skicka ett mail till {0}, och inkludera din emailadress tillsammans med deras.", - "ErrorAddingJellyfinConnectAccount1": "Det gick inte att lägga till ditt Jellyfin Connect-konto. Har du ett Jellyfin Connect-konto? Du kan skapa ett på {0}", - "ErrorAddingJellyfinConnectAccount2": "Om du fortfarande upplever problem, vänligen skicka ett mail till {0} från emailadressen som är kopplat till Jellyfin-kontot.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "Det gick inte att ta bort det här objektet från Jellyfin-servern. Kontrollera att Jellyfin-servern har skrivrättigheter till media-mappen och försök igen.", - "ErrorReachingJellyfinConnect": "Ett fel uppstod när Jellyfin Connect försökte nås. Se till att du har en aktiv internetuppkoppling och försök igen.", - "ErrorRemovingJellyfinConnectAccount": "Ett fel uppstod när Jellyfin Connect-kontot försökte tas bort. Se till att du har en aktiv internetuppkoppling och försök igen.", - "ExtraLarge": "Extra stor", - "Extras": "Extras", - "Favorite": "Favorit", - "Favorites": "Favoriter", - "FeatureRequiresJellyfinPremiere": "Den här funktionen kräver en aktiv Jellyfin Premium prenumeration.", - "Features": "Innehåll", - "File": "Fil", - "Fill": "Fyll", - "Filters": "Filter", - "Folders": "Mappar", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Få fri tillgång till Jellyfin appar för dina enheter.", - "Friday": "Fredag", - "GenreValue": "Genre: {0}", - "Genres": "Genrer", - "GenresValue": "Genrer: {0}", - "GroupBySeries": "Gruppera efter serie", - "GroupVersions": "Gruppera versioner", - "GuestStar": "Gästmedverkande", - "GuestUserNotFound": "Användaren kunde inte hittas. Se till så att namnet är korrekt och försök igen, eller pröva att ange emailadressen istället.", - "Guide": "Guide", - "HDPrograms": "HD-program", - "HeaderActiveRecordings": "Pågående inspelningar", - "HeaderAddToCollection": "Lägg till samling", - "HeaderAddToPlaylist": "Lägg till i Spellista", - "HeaderAddUpdateImage": "Lägg till/uppdatera bild", - "HeaderAlbumArtists": "Albumartister", - "HeaderAlreadyPaid": "Redan betalat?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Ljudböcker", - "HeaderAudioSettings": "Ljudinställningar", - "HeaderBecomeProjectSupporter": "Skaffa Jellyfin Premium", - "HeaderBenefitsJellyfinPremiere": "Fördelar med Jellyfin Premium", - "HeaderCancelRecording": "Avbryt inspelning", - "HeaderCancelSeries": "Avbryt serie", - "HeaderCinemaMode": "Bioläge", - "HeaderCloudSync": "Molnsynkronisering", - "HeaderConfirmRecordingCancellation": "Bekräfta avbrott av inspelning", - "HeaderContinueListening": "Fortsätt lyssna på", - "HeaderContinueWatching": "Fortsätt kolla på", - "HeaderConvertYourRecordings": "Konvertera dina inspelningar", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Radera objekt", - "HeaderDeleteItems": "Ta bort objekt", - "HeaderDisplaySettings": "Visningsinställningar", - "HeaderDownloadSettings": "Nedladdningsinställningar", - "HeaderEditImages": "Redigera bilder", - "HeaderEnabledFields": "Aktiverade fält", - "HeaderEnabledFieldsHelp": "Bocka ur ett fält för att låsa det och undvik att dess data ändras.", - "HeaderExternalIds": "Externa ID'n:", - "HeaderFavoriteAlbums": "Favoritalbum", - "HeaderFavoriteArtists": "Favoritartister", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favoritavsnitt", - "HeaderFavoriteGames": "Favoritspel", - "HeaderFavoriteMovies": "Favoritfilmer", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favoritserier", - "HeaderFavoriteSongs": "Favoritlåtar", - "HeaderFavoriteVideos": "Favoritvideos", - "HeaderFreeApps": "Gratis Jellyfin appar", - "HeaderHomeScreen": "Hemskärm", - "HeaderIdentifyItemHelp": "Ange ett eller flera sökkriterier. Ta bort kriterier för att få fler träffar.", - "HeaderInvitationSent": "Inbjudan skickad", - "HeaderJellyfinAccountAdded": "Jellyfinkontot har lagts till", - "HeaderJellyfinAccountRemoved": "Jellyfin-kontot har tagits bort", - "HeaderKeepRecording": "Fortsätt spela in", - "HeaderKeepSeries": "Behåll serie", - "HeaderLatestChannelItems": "Senaste nytt i Kanaler", - "HeaderLatestChannelMedia": "Senaste nytt i Kanaler", - "HeaderLatestFrom": "Senaste från {0}", - "HeaderLatestMedia": "Nytillkommet", - "HeaderLatestRecordings": "Senaste inspelningar", - "HeaderLearnMore": "Läs mer", - "HeaderLibraryFolders": "Biblioteksmappar", - "HeaderLibraryOrder": "Biblioteksordning", - "HeaderMetadataSettings": "Metadatainställningar", - "HeaderMusicQuality": "Musikkvalitet:", - "HeaderMyDevice": "Min enhet", - "HeaderMyDownloads": "Mina nedladdningar", - "HeaderMyMedia": "Min Media", - "HeaderMyMediaSmall": "Min Media (liten)", - "HeaderNewRecording": "Ny inspelning", - "HeaderNextEpisodePlayingInValue": "Nästa avsnitt börjar om {0}", - "HeaderNextUp": "Nästa på tur", - "HeaderNextVideoPlayingInValue": "Nästa video börjar om {0}", - "HeaderOfflineDownloads": "Offlinemedia", - "HeaderOfflineDownloadsDescription": "Ladda ner media till dina enheter för att sen spela upp dom enkelt offline.", - "HeaderOnNow": "Visas nu", - "HeaderPhotoAlbums": "Fotoalbum", - "HeaderPlayMyMedia": "Spela min media", - "HeaderPlayOn": "Spela på", - "HeaderPlaybackError": "Uppspelningsfel", - "HeaderRecordingOptions": "Inspelningsalternativ", - "HeaderRemoteControl": "Fjärrkontroll", - "HeaderRestartingJellyfinServer": "Startar om Jellyfin-servern", - "HeaderSaySomethingLike": "Säg något som...", - "HeaderSecondsValue": "{0} sekunder", - "HeaderSelectDate": "Välj datum", - "HeaderSeriesOptions": "Seriealternativ", - "HeaderSeriesStatus": "Seriestatus", - "HeaderSpecialEpisodeInfo": "Information om specialavsnitt", - "HeaderStartNow": "Starta nu", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Undertextutseende", - "HeaderSubtitleSettings": "Inställningar för undertexter", - "HeaderSyncRequiresSub": "Nedladdning kräver en aktiv Jellyfin Premiere-prenumeration.", - "HeaderTermsOfPurchase": "Köpvillkor", - "HeaderTryPlayback": "Pröva uppspelning", - "HeaderUnlockFeature": "Lås upp funktion", - "HeaderUploadImage": "Ladda upp bild", - "HeaderVideoQuality": "Videokvalitet", - "HeaderVideoType": "Videotyp", - "HeaderWaitingForWifi": "Väntar på Wifi", - "HeaderWakeServer": "Väck Server", - "HeaderYouSaid": "Du sa...", - "Help": "Hjälp", - "Hide": "Dölj", - "HideWatchedContentFromLatestMedia": "Dölj visat innehåll ifrån senaste media", - "Home": "Hem", - "Horizontal": "Horisontell", - "HowDidYouPay": "Hur betalade du?", - "IHaveJellyfinPremiere": "Jag har Jellyfin Premium", - "IPurchasedThisApp": "Jag köpte den här appen", - "Identify": "Identifiera", - "Images": "Bilder", - "ImdbRating": "IMDb-betyg", - "InstallingPackage": "Installerar {0}", - "InstantMix": "Omedelbar mix", - "InterlacedVideoNotSupported": "Interlaced video stöds inte", - "ItemCount": "{0} objekt", - "Items": "Objekt", - "KeepDownload": "Behåll nedladdning", - "KeepOnDevice": "Behåll på enhet", - "Kids": "Barn", - "Label3DFormat": "3D-format:", - "LabelAirDays": "Sändningsdagar:", - "LabelAirTime": "Sändningstid:", - "LabelAirsAfterSeason": "Sänds efter säsong:", - "LabelAirsBeforeEpisode": "Sänds före avsnitt:", - "LabelAirsBeforeSeason": "Sänds före säsong:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Albumartist:", - "LabelArtists": "Artister:", - "LabelArtistsHelp": "Separera med ; vid flera", - "LabelAudio": "Ljud:", - "LabelAudioLanguagePreference": "Önskat ljudspråk:", - "LabelBirthDate": "Födelsedatum:", - "LabelBirthYear": "Födelseår:", - "LabelBitrateMbps": "Bithastighet (Mbps):", - "LabelBurnSubtitles": "Bränn untertexter:", - "LabelChannels": "Kanaler:", - "LabelCollection": "Samling:", - "LabelCommunityRating": "Användaromdöme:", - "LabelContentType": "Innehållstyp:", - "LabelConvertTo": "Konvertera till:", - "LabelCountry": "Land:", - "LabelCriticRating": "Kritikerbetyg:", - "LabelCustomRating": "Anpassad åldersgräns:", - "LabelDashboardTheme": "Kontrollpanelstema:", - "LabelDateAdded": "Inlagd den:", - "LabelDateTimeLocale": "Språktidsformat:", - "LabelDeathDate": "Död:", - "LabelDefaultScreen": "Förvald sektion:", - "LabelDiscNumber": "Skivnummer:", - "LabelDisplayLanguage": "Visningsspråk:", - "LabelDisplayLanguageHelp": "Att översätta Jellyfin är ett pågående projekt.", - "LabelDisplayMode": "Visningsläge:", - "LabelDisplayOrder": "Visningsordning:", - "LabelDropImageHere": "Släpp en bild här, eller klicka för att bläddra.", - "LabelDropShadow": "Visa skugga:", - "LabelDynamicExternalId": "{0} ID:", - "LabelEmailAddress": "E-mailadress:", - "LabelEndDate": "Slutdatum:", - "LabelEpisodeNumber": "Avsnittsnummer:", - "LabelFont": "Typsnitt:", - "LabelHomeNetworkQuality": "Hemnätverkskvalitet:", - "LabelHomeScreenSectionValue": "Hemskärmsdel {0}:", - "LabelImageType": "Typ av bild:", - "LabelInternetQuality": "Internetkvalitet:", - "LabelItemLimit": "Max antal objekt:", - "LabelKeep:": "Behåll:", - "LabelKeepUpTo": "Behåll upp till:", - "LabelLanguage": "Språk:", - "LabelLockItemToPreventChanges": "Lås det här objektet för att förhindra ändringar", - "LabelMaxChromecastBitrate": "Strömningskvalitet för Chromecast:", - "LabelMetadataDownloadLanguage": "Önskat språk:", - "LabelName": "Namn:", - "LabelNumber": "Nr:", - "LabelOriginalAspectRatio": "Ursprungligt bildförhållande:", - "LabelOriginalTitle": "Original titel:", - "LabelOverview": "Synopsis:", - "LabelParentNumber": "Parentnummer:", - "LabelParentalRating": "Åldersgräns:", - "LabelPath": "Sökväg:", - "LabelPersonRole": "Roll:", - "LabelPersonRoleHelp": "Exempel: glassbilsförare", - "LabelPlaceOfBirth": "Födelseort:", - "LabelPlayDefaultAudioTrack": "Använd det förvalda ljudspåret oavsett språk", - "LabelPlaylist": "Spellista:", - "LabelPreferredSubtitleLanguage": "Önskat språk för undertexter:", - "LabelProfile": "Profil:", - "LabelQuality": "Kvalitet", - "LabelReasonForTranscoding": "Orsak för omkodning:", - "LabelRecord": "Spela in:", - "LabelRefreshMode": "Uppdateringsläge:", - "LabelReleaseDate": "Premiärdatum:", - "LabelRuntimeMinutes": "Speltid (min):", - "LabelScreensaver": "Skärmsläckare:", - "LabelSeasonNumber": "Säsongsnummer:", - "LabelSelectFolderGroups": "Gruppera automatiskt innehåll från dessa mappar i vyer, t ex Filmer, Musik eller TV:", - "LabelSelectFolderGroupsHelp": "Ej valda mappar kommer att visas för sig själva i en egen vy.", - "LabelShortOverview": "Kort synopsis:", - "LabelSkin": "Skal:", - "LabelSkipBackLength": "'Hoppa bakåt'-längd:", - "LabelSkipForwardLength": "'Hoppa framåt'-längd:", - "LabelSortBy": "Sortera efter:", - "LabelSortOrder": "Sortering", - "LabelSortTitle": "Sorteringstitel:", - "LabelSoundEffects": "Ljudeffekter:", - "LabelSource": "Källa:", - "LabelStartWhenPossible": "Starta när det är möjligt:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stoppa när det är möjligt:", - "LabelSubtitlePlaybackMode": "Undertextläge:", - "LabelSubtitles": "Undertexter:", - "LabelSyncJobName": "Synkjobb:", - "LabelSyncNoTargetsHelp": "Det verkar inte som att du kör några appar med stöd för offline-nedladdning.", - "LabelSyncTo": "Synka till:", - "LabelTVHomeScreen": "Hemskärm i TV-läge:", - "LabelTagline": "Slogan:", - "LabelTextBackgroundColor": "Bakgrundsfärg för text:", - "LabelTextColor": "Textfärg:", - "LabelTextSize": "Textstorlek:", - "LabelTheme": "Tema:", - "LabelTitle": "Titel:", - "LabelTrackNumber": "Spår nr", - "LabelType": "Typ:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Hemsida:", - "LabelWindowBackgroundColor": "Bakgrundsfärg för text:", - "LabelYear": "År:", - "Large": "Stor", - "LatestFromLibrary": "Senaste {0}", - "LearnHowYouCanContribute": "Se hur du kan hjälpa till.", - "LearnMore": "Läs mer", - "Like": "Gilla", - "LinksValue": "Länkar: {0}", - "List": "Lista", - "Live": "Live", - "LiveBroadcasts": "Livesändningar", - "LiveTV": "Live-TV", - "LiveTvFeatureDescription": "Strömma Live TV till vilken Jellyfin app du vill, med en kompatibel TV-tuner enhet som är installerad på din Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV kräver ett aktivt Jellyfin Premium-medlemskap.", - "Logo": "Logotyp", - "ManageRecording": "Hantera inspelning", - "MarkPlayed": "Markera som spelad", - "MarkUnplayed": "Markera som ospelad", - "MarkWatched": "Markera som visad", - "MediaIsBeingConverted": "Media håller på att konverteras till ett format som är kompatibelt med enheten som ska användas.", - "Medium": "Medium", - "Menu": "Meny", - "MessageActiveSubscriptionRequiredSeriesRecordings": "Ett aktivt Jellyfin Premium-medlemskap krävs för att skapa automatiska TV-serieinspelningar.", - "MessageAreYouSureDeleteSubtitles": "Är du säker på att du vill radera den här undertextfilen?", - "MessageConfirmRecordingCancellation": "Är du säker på att du vill avbryta denna inspelning?", - "MessageDownloadQueued": "Nedladdning köad.", - "MessageFileReadError": "Ett fel uppstod när filen lästes in. Var god försök igen.", - "MessageIfYouBlockedVoice": "Om du nekade tillgång för röståtkomst till appen så behöver du konfigurerara om innan du försöker igen.", - "MessageInvitationSentToNewUser": "Ett mail har skickats till {0} med en inbjudan att registrera sig med Jellyfin.", - "MessageInvitationSentToUser": "Ett mail har skickats till {0}, med en bekfräftelse för att acceptera din delade inbjudan.", - "MessageItemSaved": "Objektet har sparats.", - "MessageItemsAdded": "Objekt tillagda.", - "MessageJellyfinAccontRemoved": "Jellyfin-kontot har tagits bort från den här användaren.", - "MessageJellyfinAccountAdded": "Jellyfinkontot har lagts till för den här användaren.", - "MessageLeaveEmptyToInherit": "Lämna tomt för att ärva inställningarna från överordnat objekt, eller använda globalt förval.", - "MessageNoDownloadsFound": "Inga offline-nedladdningar. Ladda ner media offline genom att klicka på Ladda ner i appen.", - "MessageNoServersAvailableToConnect": "Inga servers finns tillgängliga att ansluta mot. Om du har blivit inbjuden till att dela en server, se till att acceptera nedan eller klicka på länken i mailet.", - "MessageNoSyncJobsFound": "Inga nedladdningar hittades. Ladda ner genom trycka på Ladda ner i appen.", - "MessagePendingJellyfinAccountAdded": "Jellyfin-kontot har lagts till den här användaren. Ett mail har skickats ut till ägren av kontot. Inbjudan bekräftas genom att klicka på länken i mailet.", - "MessagePlayAccessRestricted": "Uppspelning av detta innehållet är för närvarande begränsat. Kontakta din Jellyfin Server administratör för mer information.", - "MessageToValidateSupporter": "Om du har ett aktivt Jellyfin Premium-medlemskap, se till att du har ställt in Jellyfin Premium i Jellyfin Server Dashboard, som du kommer åt genom att klicka på Jellyfin Premium i huvudmenyn.", - "MessageUnlockAppWithPurchaseOrSupporter": "Lås upp denna feature med ett engångsköp, eller med ett aktivt Jellyfin Premium-medlemskap.", - "MessageUnlockAppWithSupporter": "Lås upp den här funktionen med en aktiv Jellyfin Premium prenumeration.", - "MessageWeDidntRecognizeCommand": "Ledsen, men vi känner inte igen det kommandot.", - "MinutesAfter": "minuter efter", - "MinutesBefore": "minuter före", - "Mobile": "Mobil / Platta", - "Monday": "Måndag", - "More": "Mer", - "MoveLeft": "Vänster", - "MoveRight": "Höger", - "Movies": "Filmer", - "MySubtitles": "Mina undertexter", - "Name": "Namn", - "NewCollection": "Ny samling", - "NewCollectionHelp": "Samlingar gör det möjligt att skapa personanpassade grupperingar av filmer eller annat innehåll.", - "NewCollectionNameExample": "Exemple: Star Wars-samling", - "NewEpisodes": "Nya avsnitt", - "NewEpisodesOnly": "Endast nya avsnitt", - "News": "Nyheter", - "Next": "Nästa", - "No": "Nej", - "NoItemsFound": "Inga objekt hittades.", - "NoSubtitleSearchResultsFound": "Inga resultat hittades.", - "NoSubtitles": "Inga undertexter", - "NoSubtitlesHelp": "Undertexter kommer inte visas per standard. Det kan fortfarande sättas på manuellt under uppspelning.", - "None": "Inga", - "Normal": "Normal", - "Off": "Av", - "OneChannel": "En kanal", - "OnlyForcedSubtitles": "Endast tvingande undertexter", - "OnlyForcedSubtitlesHelp": "Endast undertexter markerade som tvingande kommer att laddas.", - "OnlyImageFormats": "Endast image-format (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Öppna", - "OptionNew": "Ny...", - "Original": "Original", - "OriginalAirDateValue": "Ursprungligt sändningsdatum: {0}", - "Overview": "Översikt", - "PackageInstallCancelled": "Installationen av {0} avbröts.", - "PackageInstallCompleted": "Installationen av {0} slutfördes.", - "PackageInstallFailed": "Installationen av {0} misslyckades.", - "ParentalRating": "Parental Rating", - "People": "Personer", - "PerfectMatch": "Perfekt matchning", - "Photos": "Foton", - "PlaceFavoriteChannelsAtBeginning": "Placera favoritkanaler i början", - "Play": "Spela upp", - "PlayAllFromHere": "Spela upp alla fr o m här", - "PlayCount": "Antal visningar", - "PlayFromBeginning": "Spela från början", - "PlayNext": "Spela nästa", - "PlayNextEpisodeAutomatically": "Spela nästa avsnitt automatiskt", - "PlaybackErrorNoCompatibleStream": "Inga kompatibla strömmar finns att tillgå. Vänligen försök igen senare eller kontakta din systemadministratör för mer detaljer.", - "PlaybackErrorNotAllowed": "Du har inte tillgång att spela upp det här innehållet. Kontakta din systemadministratör för mer detaljer.", - "PlaybackErrorPlaceHolder": "Sätt in skivan för att kunna spela upp den här videon.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Visad", - "Playlists": "Spellistor", - "PleaseEnterNameOrId": "Ange ett namn eller externt id.", - "PleaseRestartServerName": "Vänligen starta om Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Välj en enhet att ladda ned till.", - "PleaseSelectTwoItems": "Var god välj minst två objekt.", - "Premiere": "Premiär", - "Premieres": "Premiärer", - "Previous": "Föregående", - "Primary": "Primär", - "PrivacyPolicy": "Sekretesspolicy", - "Producer": "Producent", - "ProductionLocations": "Produktionsplatser", - "Programs": "Program", - "PromoConvertRecordingsToStreamingFormat": "Konvertera inspelningar automatiskt till ett \"streaming-vänligt\" format med Jellyfin Premium. Inspelningar konverteras on-the-fly till MP4 eller MKV, baserat på inställningarna i Jellyfin Server.", - "Quality": "Kvalitet", - "QueueAllFromHere": "Köa alla fr o m här", - "Raised": "Upphöjd", - "RecentlyWatched": "Nyligen sedda", - "Record": "Spela in", - "RecordSeries": "Spela in serie", - "RecordingCancelled": "Inspelning avbruten.", - "RecordingScheduled": "Inspelning schemalagd", - "Recordings": "Inspelningar", - "RefFramesNotSupported": "Antal video reference frames som inte stöds", - "Refresh": "Uppdatera", - "RefreshDialogHelp": "Metadata uppdateras baserat på inställningar och internettjänster som har aktiverats under Jellyfin servers kontrollpanel.", - "RefreshMetadata": "Uppdatera metadata", - "RefreshQueued": "Uppdatering köad.", - "Reject": "Neka", - "ReleaseDate": "Releasedatum", - "RemoveDownload": "Ta bort nedladdning", - "RemoveFromCollection": "Ta bort från samling", - "RemoveFromPlaylist": "Ta bort från spellista", - "RemovingFromDevice": "Tar bort från enhet", - "Repeat": "Upprepa", - "RepeatAll": "Upprepa alla", - "RepeatEpisodes": "Upprepa avsnitt", - "RepeatMode": "Repeat-läge", - "RepeatOne": "Upprepa en gång", - "ReplaceAllMetadata": "Ersätt all metadata", - "ReplaceExistingImages": "Skriv över befintliga bilder", - "RestartPleaseWaitMessage": "Vänligen vänta medan Jellyfin-servern stängs av och startar om. Detta kan ta en minut eller två.", - "ResumeAt": "Återuppta från {0}", - "Retry": "Försök igen", - "RunAtStartup": "Kör vid uppstart", - "Runtime": "Speltid", - "Saturday": "Lördag", - "Save": "Spara", - "ScanForNewAndUpdatedFiles": "Sök efter nya och uppdaterade filer", - "Schedule": "Schema", - "Screenshot": "Skärmdump", - "Screenshots": "Skärmbilder", - "Search": "Sök", - "SearchForCollectionInternetMetadata": "Sök på internet efter grafik och metadata", - "SearchForMissingMetadata": "Sök efter saknad metadata", - "SearchForSubtitles": "Sök efter undertexter", - "SearchResults": "Sökresultat", - "SecondaryAudioNotSupported": "Ljudspårs-switching stöds inte", - "SeriesCancelled": "Serieinspelningen har avbokats.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Serieinspelning schemalagd.", - "SeriesSettings": "Serieinställningar", - "SeriesYearToPresent": "{0} - nu", - "ServerNameIsRestarting": "Jellyfin Server - {0} startas om.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} stängs ner.", - "ServerUpdateNeeded": "Den här Jellyfin servern behöver uppdateras. För att ladda ner senaste versionen, gå till {0}", - "Settings": "Inställningar", - "SettingsSaved": "Inställningarna sparade.", - "Share": "Dela", - "ShowIndicatorsFor": "Visa indikatorer för:", - "ShowTitle": "Visa titel", - "ShowYear": "Visa år", - "Shows": "Serier", - "Shuffle": "Blanda", - "SkipEpisodesAlreadyInMyLibrary": "Spela inte in avsnitt som redan finns i mitt bibliotek", - "SkipEpisodesAlreadyInMyLibraryHelp": "Avsnitt kommer att jämföras med säsongs- och avsnittsnummer, när det finns.", - "Small": "Liten", - "SmallCaps": "Små bokstäver", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Undertexter som matchar förvalsspråket kommer visas när ljudspåret är på ett annat språk.", - "Songs": "Låtar", - "Sort": "Sortera", - "SortByValue": "Sortera efter {0}", - "SortChannelsBy": "Sortera kanaler efter:", - "SortName": "Sorteringstitel", - "Sports": "Sport", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Avbryt inspelning", - "Studios": "Studior", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Dessa inställningar gäller också för alla uppspelningar på Chromecast som startas av den här enheten.", - "SubtitleAppearanceSettingsDisclaimer": "Dessa inställningar kommer inte gälla för grafiska undertexter (PGS, DVD, etc), eller undertexter som har en egen inbäddad stil (ASS/SSA).", - "SubtitleCodecNotSupported": "Undertextsformatet stöds inte", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Undertexter", - "Suggestions": "Förslag", - "Sunday": "Söndag", - "Sync": "Synk", - "SyncJobItemStatusCancelled": "Avbruten", - "SyncJobItemStatusConverting": "Konverterar", - "SyncJobItemStatusFailed": "Misslyckad", - "SyncJobItemStatusQueued": "Köad", - "SyncJobItemStatusReadyToTransfer": "Redo att överföras", - "SyncJobItemStatusRemovedFromDevice": "Borttagen från enhet", - "SyncJobItemStatusSynced": "Nedladdad", - "SyncJobItemStatusSyncedMarkForRemoval": "Tar bort från enhet", - "SyncJobItemStatusTransferring": "Överför", - "SyncUnwatchedVideosOnly": "Ladda ned endast osedda videor", - "SyncUnwatchedVideosOnlyHelp": "Endast osedda videor kommer att laddas ned, och videorna kommer tas bort från enheten när de har setts.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Etiketter", - "TagsValue": "Etiketter: {0}", - "TermsOfUse": "Användarvillkor", - "ThankYouForTryingEnjoyOneMinute": "Njut av en minuts uppspelning. Tack för att du prövar Jellyfin.", - "ThemeSongs": "Vinjetter", - "ThemeVideos": "Temavideos", - "TheseSettingsAffectSubtitlesOnThisDevice": "Dessa inställningar påverkar undertexter på den här enheten", - "Thumb": "Miniatyr", - "Thursday": "Torsdag", - "TrackCount": "{0} spår", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Omkodning", - "TryMultiSelect": "Pröva flervalsmarkering", - "TryMultiSelectMessage": "För att redigera flera mediaobjekt, klicka och håll på ett omslag och markera sedan så många du vill. Pröva nu!", - "Tuesday": "Tisdag", - "Uniform": "Uniform", - "UnlockGuide": "Lås upp guide", - "Unplayed": "Inte spelad", - "Unrated": "Ej klassad", - "UntilIDelete": "Tills jag tar bort", - "UntilSpaceNeeded": "Tills utrymme behövs", - "Up": "Upp", - "Upload": "Ladda upp", - "ValueAlbumCount": "{0} album", - "ValueDiscNumber": "Skiva {0}", - "ValueEpisodeCount": "{0} avsnitt", - "ValueGameCount": "{0} spel", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} filmer", - "ValueMusicVideoCount": "{0} musikvideor", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 avsnitt", - "ValueOneGame": "1 spel", - "ValueOneItem": "1 objekt", - "ValueOneMovie": "1 film", - "ValueOneMusicVideo": "1 musikvideo", - "ValueOneSeries": "1 serie", - "ValueOneSong": "1 låt", - "ValueSeconds": "{0} sekunder", - "ValueSeriesCount": "{0} serier", - "ValueSongCount": "{0} låtar", - "ValueSpecialEpisodeName": "Specialavsnitt - {0}", - "Vertical": "Vertikal", - "VideoBitDepthNotSupported": "Videons bitdjup stöds inte", - "VideoCodecNotSupported": "Video codec stöds inte", - "VideoFramerateNotSupported": "Videons framerate stöds inte", - "VideoLevelNotSupported": "Videonivån stöds inte", - "VideoProfileNotSupported": "Videoprofilen stöds inte", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Bildupplösning stöds inte", - "ViewAlbum": "Bläddra album", - "ViewArtist": "Bläddra artist", - "VoiceInput": "Röstinspelning", - "WakeServer": "Väck server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Lyckades!", - "Watched": "Sedd", - "Wednesday": "Onsdag", - "WifiRequiredToDownload": "En Wifi-anslutning krävs för att fortsätta nedladdningen.", - "Writer": "Manusförfattare", - "Yes": "Ja" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "L\u00e5s upp denna feature med ett eng\u00e5ngsk\u00f6p, eller med ett aktivt Emby Premium-medlemskap.", + "MessageUnlockAppWithSupporter": "L\u00e5s upp den h\u00e4r funktionen med en aktiv Emby Premium prenumeration.", + "MessageToValidateSupporter": "Om du har ett aktivt Emby Premium-medlemskap, se till att du har st\u00e4llt in Emby Premium i Emby Server Dashboard, som du kommer \u00e5t genom att klicka p\u00e5 Emby Premium i huvudmenyn.", + "ValueSpecialEpisodeName": "Specialavsnitt - {0}", + "Share": "Dela", + "Add": "L\u00e4gg till", + "ServerUpdateNeeded": "Den h\u00e4r Emby servern beh\u00f6ver uppdateras. F\u00f6r att ladda ner senaste versionen, g\u00e5 till {0}", + "LiveTvRequiresUnlock": "Live TV kr\u00e4ver ett aktivt Emby Premium-medlemskap.", + "AttributeNew": "Ny", + "Premiere": "Premi\u00e4r", + "Live": "Live", + "Repeat": "Upprepa", + "TrackCount": "{0} sp\u00e5r", + "ItemCount": "{0} objekt", + "OriginalAirDateValue": "Ursprungligt s\u00e4ndningsdatum: {0}", + "EndsAtValue": "Slutar vid: {0}", + "HeaderSelectDate": "V\u00e4lj datum", + "Watched": "Sedd", + "AirDate": "S\u00e4ndningstid", + "Played": "Visad", + "ButtonOk": "Ok", + "ButtonCancel": "Avbryt", + "AccessRestrictedTryAgainLater": "\u00c5tkomst \u00e4r begr\u00e4nsad. F\u00f6rs\u00f6k igen senare.", + "ButtonGotIt": "Ok", + "ButtonRestart": "Starta om", + "RecordingCancelled": "Inspelning avbruten.", + "SeriesCancelled": "Serieinspelningen har avbokats.", + "RecordingScheduled": "Inspelning schemalagd", + "SeriesRecordingScheduled": "Serieinspelning schemalagd.", + "HeaderNewRecording": "Ny inspelning", + "WakeServer": "V\u00e4ck server", + "HeaderWakeServer": "V\u00e4ck Server", + "AttemptingWakeServer": "F\u00f6rs\u00f6ker v\u00e4cka servern. V\u00e4nligen v\u00e4nta....", + "WakeServerSuccess": "Lyckades!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "S\u00f6ndag", + "Monday": "M\u00e5ndag", + "Tuesday": "Tisdag", + "Wednesday": "Onsdag", + "Thursday": "Torsdag", + "Friday": "Fredag", + "Saturday": "L\u00f6rdag", + "Days": "Dagar", + "SortByValue": "Sortera efter {0}", + "LabelSortBy": "Sortera efter:", + "LabelSortOrder": "Sortering", + "HeaderPhotoAlbums": "Fotoalbum", + "Photos": "Foton", + "HeaderAppearsOn": "Appears On", + "List": "Lista", + "RecordSeries": "Spela in serie", + "HeaderCinemaMode": "Biol\u00e4ge", + "HeaderCloudSync": "Molnsynkronisering", + "Downloads": "H\u00e4mtningar", + "HeaderMyDownloads": "Mina nedladdningar", + "HeaderOfflineDownloads": "Offlinemedia", + "HeaderOfflineDownloadsDescription": "Ladda ner media till dina enheter f\u00f6r att sen spela upp dom enkelt offline.", + "CloudSyncFeatureDescription": "Synka din media till molnet f\u00f6r l\u00e4tttillg\u00e4ngligt backup, arkivering och konvertering.", + "LiveTvFeatureDescription": "Str\u00f6mma Live TV till vilken Emby app du vill, med en kompatibel TV-tuner enhet som \u00e4r installerad p\u00e5 din Emby Server.", + "DvrFeatureDescription": "Schemal\u00e4gg individuella LiveTV-inspelningar, serie-inspelningar och mer med Emby DVR.", + "CinemaModeFeatureDescription": "Biol\u00e4get ger dig en bioupplevelse med trailers och anpassade intros f\u00f6re varje film.", + "HeaderFreeApps": "Gratis Emby appar", + "FreeAppsFeatureDescription": "F\u00e5 fri tillg\u00e5ng till Emby appar f\u00f6r dina enheter.", + "HeaderBecomeProjectSupporter": "Skaffa Emby Premium", + "MessageActiveSubscriptionRequiredSeriesRecordings": "Ett aktivt Emby Premium-medlemskap kr\u00e4vs f\u00f6r att skapa automatiska TV-serieinspelningar.", + "LabelEmailAddress": "E-mailadress:", + "PromoConvertRecordingsToStreamingFormat": "Konvertera inspelningar automatiskt till ett \"streaming-v\u00e4nligt\" format med Emby Premium. Inspelningar konverteras on-the-fly till MP4 eller MKV, baserat p\u00e5 inst\u00e4llningarna i Emby Server.", + "FeatureRequiresEmbyPremiere": "Den h\u00e4r funktionen kr\u00e4ver en aktiv Emby Premium prenumeration.", + "HeaderConvertYourRecordings": "Konvertera dina inspelningar", + "Record": "Spela in", + "Save": "Spara", + "Edit": "\u00c4ndra", + "Download": "Ladda ned", + "Downloaded": "Nedladdade", + "Downloading": "Laddar ner", + "Advanced": "Avancerat", + "Delete": "Ta bort", + "HeaderDeleteItem": "Radera objekt", + "ConfirmDeleteItem": "Tar du bort det h\u00e4r objeketet s\u00e5 tas det bort fr\u00e5n b\u00e5de ditt filsystem och mediabibliotek. \u00c4r du s\u00e4ker p\u00e5 att du vill forts\u00e4tta?", + "Refresh": "Uppdatera", + "RefreshQueued": "Uppdatering k\u00f6ad.", + "AddToCollection": "L\u00e4gg till samling", + "HeaderAddToCollection": "L\u00e4gg till samling", + "NewCollection": "Ny samling", + "LabelCollection": "Samling:", + "Help": "Hj\u00e4lp", + "LabelDisplayMode": "Visningsl\u00e4ge:", + "Desktop": "Skrivbord", + "Mobile": "Mobil \/ Platta", + "TV": "TV", + "DisplayModeHelp": "V\u00e4lj vilken typ av sk\u00e4rm som du k\u00f6r Emby p\u00e5.", + "LabelDisplayLanguage": "Visningsspr\u00e5k:", + "LabelDisplayLanguageHelp": "Att \u00f6vers\u00e4tta Emby \u00e4r ett p\u00e5g\u00e5ende projekt.", + "LearnHowYouCanContribute": "Se hur du kan hj\u00e4lpa till.", + "NewCollectionHelp": "Samlingar g\u00f6r det m\u00f6jligt att skapa personanpassade grupperingar av filmer eller annat inneh\u00e5ll.", + "SearchForCollectionInternetMetadata": "S\u00f6k p\u00e5 internet efter grafik och metadata", + "DisplayMissingEpisodesWithinSeasons": "Visa saknade avsnitt i s\u00e4songer", + "DisplayMissingEpisodesWithinSeasonsHelp": "Detta m\u00e5ste ocks\u00e5 vara aktiverat f\u00f6r TV-bibliotek p\u00e5 Emby-servern.", + "EnableThemeSongs": "Aktivera ledmotiv", + "EnableBackdrops": "Aktivera fondbilder", + "EnableThemeSongsHelp": "Om aktiverat spelas ledmotiv upp vid bl\u00e4ddring i biblioteket.", + "EnableBackdropsHelp": "Om aktiverat visas fondbilder i bakgrunden av vissa sidor vid bl\u00e4ddring i biblioteket.", + "EnableThemeVideos": "Aktivera tema-videos", + "EnableThemeVideosHelp": "Visar tema-videos i bakgrunden n\u00e4r man bl\u00e4ddrar i biblioteket.", + "RunAtStartup": "K\u00f6r vid uppstart", + "LabelScreensaver": "Sk\u00e4rmsl\u00e4ckare:", + "LabelSoundEffects": "Ljudeffekter:", + "LabelSkin": "Skal:", + "LabelName": "Namn:", + "NewCollectionNameExample": "Exemple: Star Wars-samling", + "MessageItemsAdded": "Objekt tillagda.", + "OptionNew": "Ny...", + "LabelPlaylist": "Spellista:", + "AddToPlaylist": "L\u00e4gg till i spellista", + "HeaderAddToPlaylist": "L\u00e4gg till i Spellista", + "Subtitles": "Undertexter", + "LabelTheme": "Tema:", + "LabelDashboardTheme": "Kontrollpanelstema:", + "SearchForSubtitles": "S\u00f6k efter undertexter", + "LabelLanguage": "Spr\u00e5k:", + "Search": "S\u00f6k", + "NoSubtitleSearchResultsFound": "Inga resultat hittades.", + "File": "Fil", + "MessageAreYouSureDeleteSubtitles": "\u00c4r du s\u00e4ker p\u00e5 att du vill radera den h\u00e4r undertextfilen?", + "ConfirmDeletion": "Bekr\u00e4fta radering", + "MySubtitles": "Mina undertexter", + "MessageDownloadQueued": "Nedladdning k\u00f6ad.", + "EditSubtitles": "\u00c4ndra undertexter", + "UnlockGuide": "L\u00e5s upp guide", + "RefreshMetadata": "Uppdatera metadata", + "ReplaceExistingImages": "Skriv \u00f6ver befintliga bilder", + "ReplaceAllMetadata": "Ers\u00e4tt all metadata", + "SearchForMissingMetadata": "S\u00f6k efter saknad metadata", + "LabelRefreshMode": "Uppdateringsl\u00e4ge:", + "NoItemsFound": "Inga objekt hittades.", + "HeaderSaySomethingLike": "S\u00e4g n\u00e5got som...", + "ButtonTryAgain": "F\u00f6rs\u00f6k igen", + "HeaderYouSaid": "Du sa...", + "MessageWeDidntRecognizeCommand": "Ledsen, men vi k\u00e4nner inte igen det kommandot.", + "MessageIfYouBlockedVoice": "Om du nekade tillg\u00e5ng f\u00f6r r\u00f6st\u00e5tkomst till appen s\u00e5 beh\u00f6ver du konfigurerara om innan du f\u00f6rs\u00f6ker igen.", + "ValueDiscNumber": "Skiva {0}", + "Unrated": "Ej klassad", + "Favorite": "Favorit", + "Like": "Gilla", + "Dislike": "Ogilla", + "RefreshDialogHelp": "Metadata uppdateras baserat p\u00e5 inst\u00e4llningar och internettj\u00e4nster som har aktiverats under Emby servers kontrollpanel.", + "Open": "\u00d6ppna", + "Play": "Spela upp", + "AddToPlayQueue": "L\u00e4gg till i spelk\u00f6", + "Shuffle": "Blanda", + "Identify": "Identifiera", + "EditImages": "\u00c4ndra bilder", + "EditMetadata": "Redigera metadata", + "Convert": "Konvertera", + "Sync": "Synk", + "InstantMix": "Omedelbar mix", + "ViewAlbum": "Bl\u00e4ddra album", + "ViewArtist": "Bl\u00e4ddra artist", + "QueueAllFromHere": "K\u00f6a alla fr o m h\u00e4r", + "PlayAllFromHere": "Spela upp alla fr o m h\u00e4r", + "PlayFromBeginning": "Spela fr\u00e5n b\u00f6rjan", + "ResumeAt": "\u00c5teruppta fr\u00e5n {0}", + "RemoveFromPlaylist": "Ta bort fr\u00e5n spellista", + "RemoveFromCollection": "Ta bort fr\u00e5n samling", + "Sort": "Sortera", + "Trailer": "Trailer", + "MarkPlayed": "Markera som spelad", + "MarkUnplayed": "Markera som ospelad", + "GroupVersions": "Gruppera versioner", + "PleaseSelectTwoItems": "Var god v\u00e4lj minst tv\u00e5 objekt.", + "TryMultiSelect": "Pr\u00f6va flervalsmarkering", + "TryMultiSelectMessage": "F\u00f6r att redigera flera mediaobjekt, klicka och h\u00e5ll p\u00e5 ett omslag och markera sedan s\u00e5 m\u00e5nga du vill. Pr\u00f6va nu!", + "HeaderConfirmRecordingCancellation": "Bekr\u00e4fta avbrott av inspelning", + "MessageConfirmRecordingCancellation": "\u00c4r du s\u00e4ker p\u00e5 att du vill avbryta denna inspelning?", + "Error": "Fel", + "VoiceInput": "R\u00f6stinspelning", + "LabelContentType": "Inneh\u00e5llstyp:", + "LabelPath": "S\u00f6kv\u00e4g:", + "Playlists": "Spellistor", + "LabelTitle": "Titel:", + "LabelOriginalTitle": "Original titel:", + "LabelSortTitle": "Sorteringstitel:", + "LabelDateAdded": "Inlagd den:", + "DateAdded": "Inlagd den", + "DatePlayed": "Senast visad", + "ConfigureDateAdded": "Konfigurera hur tillagt datum best\u00e4ms i Emby servern under Biblioteksinst\u00e4llningar", + "LabelStatus": "Status:", + "LabelArtists": "Artister:", + "LabelArtistsHelp": "Separera med ; vid flera", + "HeaderAlbumArtists": "Albumartister", + "LabelAlbumArtists": "Albumartist:", + "LabelAlbum": "Album:", + "Artists": "Artister", + "ImdbRating": "IMDb-betyg", + "CommunityRating": "Anv\u00e4ndaromd\u00f6me", + "LabelCommunityRating": "Anv\u00e4ndaromd\u00f6me:", + "LabelCriticRating": "Kritikerbetyg:", + "CriticRating": "Kritikerbetyg", + "LabelWebsite": "Hemsida:", + "LabelTagline": "Slogan:", + "LabelOverview": "Synopsis:", + "LabelShortOverview": "Kort synopsis:", + "LabelReleaseDate": "Premi\u00e4rdatum:", + "LabelYear": "\u00c5r:", + "LabelPlaceOfBirth": "F\u00f6delseort:", + "Aired": "S\u00e4ndes", + "LabelAirDays": "S\u00e4ndningsdagar:", + "LabelAirTime": "S\u00e4ndningstid:", + "LabelRuntimeMinutes": "Speltid (min):", + "LabelParentalRating": "\u00c5ldersgr\u00e4ns:", + "LabelCustomRating": "Anpassad \u00e5ldersgr\u00e4ns:", + "LabelOriginalAspectRatio": "Ursprungligt bildf\u00f6rh\u00e5llande:", + "Label3DFormat": "3D-format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "Nedladdningar: {0}", + "PerfectMatch": "Perfekt matchning", + "EnableExternalVideoPlayers": "Aktivera externa videospelare", + "EnableExternalVideoPlayersHelp": "En extern uppspelningsmeny kommer att visas n\u00e4r man startar en videouppspelning.", + "HeaderSpecialEpisodeInfo": "Information om specialavsnitt", + "LabelAirsBeforeSeason": "S\u00e4nds f\u00f6re s\u00e4song:", + "LabelAirsAfterSeason": "S\u00e4nds efter s\u00e4song:", + "LabelAirsBeforeEpisode": "S\u00e4nds f\u00f6re avsnitt:", + "HeaderExternalIds": "Externa ID'n:", + "HeaderDisplaySettings": "Visningsinst\u00e4llningar", + "LabelDisplayOrder": "Visningsordning:", + "Display": "Visning", + "Countries": "L\u00e4nder", + "Genres": "Genrer", + "Studios": "Studior", + "Tags": "Etiketter", + "HeaderMetadataSettings": "Metadatainst\u00e4llningar", + "People": "Personer", + "LabelMetadataDownloadLanguage": "\u00d6nskat spr\u00e5k:", + "LabelLockItemToPreventChanges": "L\u00e5s det h\u00e4r objektet f\u00f6r att f\u00f6rhindra \u00e4ndringar", + "MessageLeaveEmptyToInherit": "L\u00e4mna tomt f\u00f6r att \u00e4rva inst\u00e4llningarna fr\u00e5n \u00f6verordnat objekt, eller anv\u00e4nda globalt f\u00f6rval.", + "LabelCountry": "Land:", + "LabelDynamicExternalId": "{0} ID:", + "LabelBirthYear": "F\u00f6delse\u00e5r:", + "LabelBirthDate": "F\u00f6delsedatum:", + "LabelDeathDate": "D\u00f6d:", + "LabelEndDate": "Slutdatum:", + "LabelSeasonNumber": "S\u00e4songsnummer:", + "LabelEpisodeNumber": "Avsnittsnummer:", + "LabelTrackNumber": "Sp\u00e5r nr", + "LabelNumber": "Nr:", + "LabelDiscNumber": "Skivnummer:", + "LabelParentNumber": "Parentnummer:", + "SortName": "Sorteringstitel", + "ReleaseDate": "Releasedatum", + "Continuing": "P\u00e5g\u00e5ende", + "Ended": "Avslutad", + "HeaderEnabledFields": "Aktiverade f\u00e4lt", + "HeaderEnabledFieldsHelp": "Bocka ur ett f\u00e4lt f\u00f6r att l\u00e5sa det och undvik att dess data \u00e4ndras.", + "Backdrops": "Fondbilder", + "Images": "Bilder", + "Runtime": "Speltid", + "ProductionLocations": "Produktionsplatser", + "BirthLocation": "F\u00f6delseort", + "ParentalRating": "Parental Rating", + "PlayCount": "Antal visningar", + "Name": "Namn", + "Overview": "\u00d6versikt", + "LabelType": "Typ:", + "LabelPersonRole": "Roll:", + "LabelPersonRoleHelp": "Exempel: glassbilsf\u00f6rare", + "Actor": "Sk\u00e5despelare", + "Composer": "Komposit\u00f6r", + "Director": "Regiss\u00f6r", + "GuestStar": "G\u00e4stmedverkande", + "Producer": "Producent", + "Writer": "Manusf\u00f6rfattare", + "MessageNoSyncJobsFound": "Inga nedladdningar hittades. Ladda ner genom trycka p\u00e5 Ladda ner i appen.", + "MessageNoDownloadsFound": "Inga offline-nedladdningar. Ladda ner media offline genom att klicka p\u00e5 Ladda ner i appen.", + "InstallingPackage": "Installerar {0}", + "PackageInstallCompleted": "Installationen av {0} slutf\u00f6rdes.", + "PackageInstallFailed": "Installationen av {0} misslyckades.", + "PackageInstallCancelled": "Installationen av {0} avbr\u00f6ts.", + "SeriesYearToPresent": "{0} - nu", + "ValueOneItem": "1 objekt", + "ValueOneSong": "1 l\u00e5t", + "ValueSongCount": "{0} l\u00e5tar", + "ValueOneMovie": "1 film", + "ValueMovieCount": "{0} filmer", + "ValueOneSeries": "1 serie", + "ValueSeriesCount": "{0} serier", + "ValueOneEpisode": "1 avsnitt", + "ValueEpisodeCount": "{0} avsnitt", + "ValueOneGame": "1 spel", + "ValueGameCount": "{0} spel", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} album", + "ValueOneMusicVideo": "1 musikvideo", + "ValueMusicVideoCount": "{0} musikvideor", + "ValueMinutes": "{0} min", + "Albums": "Album", + "Songs": "L\u00e5tar", + "Books": "B\u00f6cker", + "HeaderAudioBooks": "Ljudb\u00f6cker", + "HeaderIdentifyItemHelp": "Ange ett eller flera s\u00f6kkriterier. Ta bort kriterier f\u00f6r att f\u00e5 fler tr\u00e4ffar.", + "PleaseEnterNameOrId": "Ange ett namn eller externt id.", + "MessageItemSaved": "Objektet har sparats.", + "SearchResults": "S\u00f6kresultat", + "ServerNameIsRestarting": "Emby Server - {0} startas om.", + "ServerNameIsShuttingDown": "Emby Server - {0} st\u00e4ngs ner.", + "HeaderDeleteItems": "Ta bort objekt", + "ConfirmDeleteItems": "Tar du bort dessa objekt tas dom ocks\u00e5 bort ifr\u00e5n b\u00e5de ditt filsystem och mediabibliotek. \u00c4r du s\u00e4ker p\u00e5 att du vill forts\u00e4tta?", + "PleaseRestartServerName": "V\u00e4nligen starta om Emby Server - {0}.", + "LabelSyncJobName": "Synkjobb:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Kvalitet", + "LabelSyncNoTargetsHelp": "Det verkar inte som att du k\u00f6r n\u00e5gra appar med st\u00f6d f\u00f6r offline-nedladdning.", + "DownloadingDots": "Laddar ner...", + "HeaderSyncRequiresSub": "Nedladdning kr\u00e4ver en aktiv Emby Premiere-prenumeration.", + "LearnMore": "L\u00e4s mer", + "LabelProfile": "Profil:", + "LabelBitrateMbps": "Bithastighet (Mbps):", + "ConvertUnwatchedVideosOnly": "Konvertera endast osedda videos", + "SyncUnwatchedVideosOnly": "Ladda ned endast osedda videor", + "ConvertUnwatchedVideosOnlyHelp": "Endast osedda videos kommer att konverteras.", + "SyncUnwatchedVideosOnlyHelp": "Endast osedda videor kommer att laddas ned, och videorna kommer tas bort fr\u00e5n enheten n\u00e4r de har setts.", + "AutomaticallySyncNewContent": "Ladda ned nytt inneh\u00e5ll automatiskt", + "AutomaticallySyncNewContentHelp": "Nytt inneh\u00e5ll till den h\u00e4r mappen kommer automatiskt att laddas ned till enheten.", + "AutomaticallyConvertNewContent": "Konvertera nytt inneh\u00e5ll automatiskt", + "AutomaticallyConvertNewContentHelp": "Nytt inneh\u00e5ll till den h\u00e4r mappen kommer automatiskt att konverteras.", + "LabelItemLimit": "Max antal objekt:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "V\u00e4lj en enhet att ladda ned till.", + "Screenshots": "Sk\u00e4rmbilder", + "MoveRight": "H\u00f6ger", + "MoveLeft": "V\u00e4nster", + "ConfirmDeleteImage": "Ta bort bild?", + "HeaderEditImages": "Redigera bilder", + "Settings": "Inst\u00e4llningar", + "ShowIndicatorsFor": "Visa indikatorer f\u00f6r:", + "NewEpisodes": "Nya avsnitt", + "Episodes": "Avsnitt", + "HDPrograms": "HD-program", + "Programs": "Program", + "LiveBroadcasts": "Lives\u00e4ndningar", + "Premieres": "Premi\u00e4rer", + "RepeatEpisodes": "Upprepa avsnitt", + "DvrSubscriptionRequired": "Emby DVR kr\u00e4ver en aktiv Emby Premium prenumeration.", + "HeaderCancelRecording": "Avbryt inspelning", + "CancelRecording": "Avbryt inspelning", + "HeaderKeepRecording": "Forts\u00e4tt spela in", + "HeaderCancelSeries": "Avbryt serie", + "HeaderKeepSeries": "Beh\u00e5ll serie", + "HeaderLearnMore": "L\u00e4s mer", + "DeleteMedia": "Ta bort media", + "SeriesSettings": "Serieinst\u00e4llningar", + "HeaderRecordingOptions": "Inspelningsalternativ", + "CancelSeries": "Avbryt serie", + "DoNotRecord": "Spela inte in", + "HeaderSeriesOptions": "Seriealternativ", + "LabelChannels": "Kanaler:", + "ChannelNameOnly": "Endast kanal {0}", + "Anytime": "N\u00e4r som helst", + "AnyLanguage": "Vilket spr\u00e5k som helst", + "AroundTime": "Runt {0}", + "All": "Alla", + "AllChannels": "Alla kanaler", + "LabelRecord": "Spela in:", + "NewEpisodesOnly": "Endast nya avsnitt", + "AllEpisodes": "Alla avsnitt", + "LabelStartWhenPossible": "Starta n\u00e4r det \u00e4r m\u00f6jligt:", + "LabelStopWhenPossible": "Stoppa n\u00e4r det \u00e4r m\u00f6jligt:", + "MinutesBefore": "minuter f\u00f6re", + "MinutesAfter": "minuter efter", + "SkipEpisodesAlreadyInMyLibrary": "Spela inte in avsnitt som redan finns i mitt bibliotek", + "SkipEpisodesAlreadyInMyLibraryHelp": "Avsnitt kommer att j\u00e4mf\u00f6ras med s\u00e4songs- och avsnittsnummer, n\u00e4r det finns.", + "LabelKeepUpTo": "Beh\u00e5ll upp till:", + "AsManyAsPossible": "S\u00e5 m\u00e5nga som m\u00f6jligt", + "DefaultErrorMessage": "Ett fel uppstd vid beg\u00e4ran. F\u00f6rs\u00f6k igen senare.", + "LabelKeep:": "Beh\u00e5ll:", + "UntilIDelete": "Tills jag tar bort", + "UntilSpaceNeeded": "Tills utrymme beh\u00f6vs", + "Categories": "Kategorier", + "Sports": "Sport", + "News": "Nyheter", + "Movies": "Filmer", + "Kids": "Barn", + "EnableColorCodedBackgrounds": "Aktivera f\u00e4rgkodade bakgrundsbilder", + "SortChannelsBy": "Sortera kanaler efter:", + "RecentlyWatched": "Nyligen sedda", + "ChannelNumber": "Kanalnummer", + "HeaderBenefitsEmbyPremiere": "F\u00f6rdelar med Emby Premium", + "ThankYouForTryingEnjoyOneMinute": "Njut av en minuts uppspelning. Tack f\u00f6r att du pr\u00f6var Emby.", + "HeaderTryPlayback": "Pr\u00f6va uppspelning", + "HowDidYouPay": "Hur betalade du?", + "IHaveEmbyPremiere": "Jag har Emby Premium", + "IPurchasedThisApp": "Jag k\u00f6pte den h\u00e4r appen", + "ButtonRestorePreviousPurchase": "\u00c5terst\u00e4ll k\u00f6p", + "ButtonUnlockWithPurchase": "L\u00e5s upp med k\u00f6p", + "ButtonUnlockPrice": "L\u00e5s upp {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premium M\u00e5nadsvis {0}", + "HeaderAlreadyPaid": "Redan betalat?", + "ButtonPlayOneMinute": "Spela en minut", + "PlaceFavoriteChannelsAtBeginning": "Placera favoritkanaler i b\u00f6rjan", + "HeaderUnlockFeature": "L\u00e5s upp funktion", + "MessageDidYouKnowCinemaMode": "Visste du att med Emby Premium, s\u00e5 kan du ut\u00f6ka dina upplevelser med features som Biol\u00e4ge?", + "MessageDidYouKnowCinemaMode2": "Biol\u00e4get ger dig en \u00e4kta biok\u00e4nsla med trailers och anpassade intros innan huvudfilmen.", + "HeaderPlayMyMedia": "Spela min media", + "HeaderDiscoverEmbyPremiere": "Uppt\u00e4ck Emby Premium", + "Items": "Objekt", + "OneChannel": "En kanal", + "ConfirmRemoveDownload": "Ta bort nedladdning?", + "RemoveDownload": "Ta bort nedladdning", + "KeepDownload": "Beh\u00e5ll nedladdning", + "AddedOnValue": "Tillagd {0}", + "RemovingFromDevice": "Tar bort fr\u00e5n enhet", + "KeepOnDevice": "Beh\u00e5ll p\u00e5 enhet", + "CancelDownload": "Avbryt nedladdning", + "SyncJobItemStatusReadyToTransfer": "Redo att \u00f6verf\u00f6ras", + "SyncJobItemStatusSyncedMarkForRemoval": "Tar bort fr\u00e5n enhet", + "SyncJobItemStatusQueued": "K\u00f6ad", + "SyncJobItemStatusConverting": "Konverterar", + "SyncJobItemStatusTransferring": "\u00d6verf\u00f6r", + "SyncJobItemStatusSynced": "Nedladdad", + "SyncJobItemStatusFailed": "Misslyckad", + "SyncJobItemStatusRemovedFromDevice": "Borttagen fr\u00e5n enhet", + "SyncJobItemStatusCancelled": "Avbruten", + "Retry": "F\u00f6rs\u00f6k igen", + "HeaderMyDevice": "Min enhet", + "Continue": "Forts\u00e4tt", + "ContinueInSecondsValue": "Forts\u00e4tt om {0} sekunder.", + "HeaderRemoteControl": "Fj\u00e4rrkontroll", + "Disconnect": "Koppla bort", + "EnableDisplayMirroring": "Aktivera sk\u00e4rmspegling", + "HeaderPlayOn": "Spela p\u00e5", + "Quality": "Kvalitet", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "F\u00f6r att \u00e5terst\u00e4lla ditt tidigare k\u00f6p, se till s\u00e5 att du \u00e4r inloggad p\u00e5 enheten med samma Google (eller Amazon) konto som genomf\u00f6rde k\u00f6pet. Kolla s\u00e5 att appstore \u00e4r aktiverat och att det inte \u00e4r begr\u00e4nsat med barnsp\u00e4rrar samt att det finns en aktiv internetuppkoppling. Du beh\u00f6ver endast g\u00f6ra detta en g\u00e5ng f\u00f6r att \u00e5terst\u00e4lla ditt tidigare k\u00f6p.", + "AspectRatio": "Bildf\u00f6rh\u00e5llande", + "Original": "Original", + "Fill": "Fyll", + "BestFit": "Anpassad", + "MessageNoServersAvailableToConnect": "Inga servers finns tillg\u00e4ngliga att ansluta mot. Om du har blivit inbjuden till att dela en server, se till att acceptera nedan eller klicka p\u00e5 l\u00e4nken i mailet.", + "MessagePlayAccessRestricted": "Uppspelning av detta inneh\u00e5llet \u00e4r f\u00f6r n\u00e4rvarande begr\u00e4nsat. Kontakta din Emby Server administrat\u00f6r f\u00f6r mer information.", + "Accept": "Acceptera", + "Reject": "Neka", + "Connect": "Anslut", + "HeaderMyMedia": "Min Media", + "HeaderMyMediaSmall": "Min Media (liten)", + "LatestFromLibrary": "Senaste {0}", + "ContinueWatching": "Forts\u00e4tt titta p\u00e5", + "HeaderLatestChannelMedia": "Senaste nytt i Kanaler", + "HeaderContinueWatching": "Forts\u00e4tt kolla p\u00e5", + "HeaderContinueListening": "Forts\u00e4tt lyssna p\u00e5", + "HeaderActiveRecordings": "P\u00e5g\u00e5ende inspelningar", + "HeaderLatestRecordings": "Senaste inspelningar", + "LabelSyncTo": "Synka till:", + "LabelConvertTo": "Konvertera till:", + "Next": "N\u00e4sta", + "LabelSource": "K\u00e4lla:", + "LabelVersion": "Version:", + "AllLanguages": "Alla spr\u00e5k", + "Previous": "F\u00f6reg\u00e5ende", + "HeaderNextUp": "N\u00e4sta p\u00e5 tur", + "HeaderLatestFrom": "Senaste fr\u00e5n {0}", + "LabelHomeScreenSectionValue": "Hemsk\u00e4rmsdel {0}:", + "SettingsSaved": "Inst\u00e4llningarna sparade.", + "None": "Inga", + "More": "Mer", + "Up": "Upp", + "Down": "Ner", + "Home": "Hem", + "Favorites": "Favoriter", + "HeaderHomeScreen": "Hemsk\u00e4rm", + "HeaderLatestChannelItems": "Senaste nytt i Kanaler", + "HeaderLibraryOrder": "Biblioteksordning", + "HideWatchedContentFromLatestMedia": "D\u00f6lj visat inneh\u00e5ll ifr\u00e5n senaste media", + "HeaderOnNow": "Visas nu", + "HeaderPlaybackError": "Uppspelningsfel", + "PlaybackErrorNotAllowed": "Du har inte tillg\u00e5ng att spela upp det h\u00e4r inneh\u00e5llet. Kontakta din systemadministrat\u00f6r f\u00f6r mer detaljer.", + "PlaybackErrorNoCompatibleStream": "Inga kompatibla str\u00f6mmar finns att tillg\u00e5. V\u00e4nligen f\u00f6rs\u00f6k igen senare eller kontakta din systemadministrat\u00f6r f\u00f6r mer detaljer.", + "PlaybackErrorPlaceHolder": "S\u00e4tt in skivan f\u00f6r att kunna spela upp den h\u00e4r videon.", + "Guide": "Guide", + "Suggestions": "F\u00f6rslag", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Samlingar", + "LabelSelectFolderGroups": "Gruppera automatiskt inneh\u00e5ll fr\u00e5n dessa mappar i vyer, t ex Filmer, Musik eller TV:", + "LabelSelectFolderGroupsHelp": "Ej valda mappar kommer att visas f\u00f6r sig sj\u00e4lva i en egen vy.", + "Folders": "Mappar", + "DisplayInOtherHomeScreenSections": "Visa sektioner p\u00e5 hemsk\u00e4rmen som till exempel senast media och forts\u00e4tt kolla p\u00e5", + "DisplayInMyMedia": "Visa p\u00e5 hemsk\u00e4rmen", + "Shows": "Serier", + "HeaderLibraryFolders": "Biblioteksmappar", + "HeaderTermsOfPurchase": "K\u00f6pvillkor", + "PrivacyPolicy": "Sekretesspolicy", + "TermsOfUse": "Anv\u00e4ndarvillkor", + "RepeatMode": "Repeat-l\u00e4ge", + "RepeatOne": "Upprepa en g\u00e5ng", + "RepeatAll": "Upprepa alla", + "LabelDefaultScreen": "F\u00f6rvald sektion:", + "ConfirmEndPlayerSession": "Vill du st\u00e4nga ner Emby p\u00e5 {0}?", + "Yes": "Ja", + "No": "Nej", + "LiveTV": "Live-TV", + "Schedule": "Schema", + "Recordings": "Inspelningar", + "MarkWatched": "Markera som visad", + "ScanForNewAndUpdatedFiles": "S\u00f6k efter nya och uppdaterade filer", + "DirectStreamHelp1": "Inneh\u00e5llet \u00e4r kompatibelt med enheten vad g\u00e4ller uppl\u00f6sning och mediatyp (H.264, AC3, etc.) men det \u00e4r en inkompatibel filkontainer (.mkv, .avi, .wmv etc.). Video-filen kommer att packas om live innan str\u00f6mningen startar till enheten.", + "DirectStreamHelp2": "Direktstr\u00f6mning av en fil anv\u00e4nder v\u00e4ldigt lite resurser av CPU'n utan att bildkvaliten f\u00f6rs\u00e4mras.", + "MediaIsBeingConverted": "Media h\u00e5ller p\u00e5 att konverteras till ett format som \u00e4r kompatibelt med enheten som ska anv\u00e4ndas.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Orsak f\u00f6r omkodning:", + "DirectPlaying": "Direktuppspelning", + "DirectStreaming": "Direktstr\u00f6mning", + "Transcoding": "Omkodning", + "ContainerBitrateExceedsLimit": "Medians bithastighet \u00f6verskrider begr\u00e4nsningen", + "VideoCodecNotSupported": "Video codec st\u00f6ds inte", + "AudioCodecNotSupported": "Ljud codec st\u00f6ds inte", + "SubtitleCodecNotSupported": "Undertextsformatet st\u00f6ds inte", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Kontainern st\u00f6ds inte", + "VideoLevelNotSupported": "Videoniv\u00e5n st\u00f6ds inte", + "AudioBitrateNotSupported": "Ljudbithastigheten st\u00f6ds inte", + "AudioChannelsNotSupported": "Ljudkanaler st\u00f6ds inte", + "VideoResolutionNotSupported": "Bilduppl\u00f6sning st\u00f6ds inte", + "AudioProfileNotSupported": "Ljudprofil st\u00f6ds inte", + "AudioSampleRateNotSupported": "Ljudsamplingrate st\u00f6ds inte", + "AnamorphicVideoNotSupported": "Anamorphic video st\u00f6ds inte", + "InterlacedVideoNotSupported": "Interlaced video st\u00f6ds inte", + "SecondaryAudioNotSupported": "Ljudsp\u00e5rs-switching st\u00f6ds inte", + "ErrorRemovingEmbyConnectAccount": "Ett fel uppstod n\u00e4r Emby Connect-kontot f\u00f6rs\u00f6kte tas bort. Se till att du har en aktiv internetuppkoppling och f\u00f6rs\u00f6k igen.", + "HeaderEmbyAccountRemoved": "Emby-kontot har tagits bort", + "MessageEmbyAccontRemoved": "Emby-kontot har tagits bort fr\u00e5n den h\u00e4r anv\u00e4ndaren.", + "HeaderInvitationSent": "Inbjudan skickad", + "MessageInvitationSentToUser": "Ett mail har skickats till {0}, med en bekfr\u00e4ftelse f\u00f6r att acceptera din delade inbjudan.", + "MessageInvitationSentToNewUser": "Ett mail har skickats till {0} med en inbjudan att registrera sig med Emby.", + "GuestUserNotFound": "Anv\u00e4ndaren kunde inte hittas. Se till s\u00e5 att namnet \u00e4r korrekt och f\u00f6rs\u00f6k igen, eller pr\u00f6va att ange emailadressen ist\u00e4llet.", + "ErrorReachingEmbyConnect": "Ett fel uppstod n\u00e4r Emby Connect f\u00f6rs\u00f6kte n\u00e5s. Se till att du har en aktiv internetuppkoppling och f\u00f6rs\u00f6k igen.", + "ErrorAddingEmbyConnectAccount1": "Det gick inte att l\u00e4gga till ditt Emby Connect-konto. Har du ett Emby Connect-konto? Du kan skapa ett p\u00e5 {0}", + "ErrorAddingEmbyConnectAccount2": "Om du fortfarande upplever problem, v\u00e4nligen skicka ett mail till {0} fr\u00e5n emailadressen som \u00e4r kopplat till Emby-kontot.", + "ErrorAddingGuestAccount1": "Det gick inte att l\u00e4gga till Emby Connect-kontot. Har din g\u00e4st ett Emby-konto? Dom kan skapa ett p\u00e5 {0}", + "ErrorAddingGuestAccount2": "Om du fortfarande upplever problem, v\u00e4nligen skicka ett mail till {0}, och inkludera din emailadress tillsammans med deras.", + "MessageEmbyAccountAdded": "Embykontot har lagts till f\u00f6r den h\u00e4r anv\u00e4ndaren.", + "MessagePendingEmbyAccountAdded": "Emby-kontot har lagts till den h\u00e4r anv\u00e4ndaren. Ett mail har skickats ut till \u00e4gren av kontot. Inbjudan bekr\u00e4ftas genom att klicka p\u00e5 l\u00e4nken i mailet.", + "HeaderEmbyAccountAdded": "Embykontot har lagts till", + "LabelSubtitlePlaybackMode": "Undertextl\u00e4ge:", + "ErrorDeletingItem": "Det gick inte att ta bort det h\u00e4r objektet fr\u00e5n Emby-servern. Kontrollera att Emby-servern har skrivr\u00e4ttigheter till media-mappen och f\u00f6rs\u00f6k igen.", + "NoSubtitles": "Inga undertexter", + "Default": "Standard", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Liten", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Stor", + "ExtraLarge": "Extra stor", + "OnlyForcedSubtitles": "Endast tvingande undertexter", + "AlwaysPlaySubtitles": "Visa alltid undertexter", + "DefaultSubtitlesHelp": "Undertexter visas baserat p\u00e5 standardspr\u00e5k och tvingande undertexter i den inb\u00e4ddade metadatan. F\u00f6rvalsspr\u00e5k kommer v\u00e4ljas n\u00e4r fler val \u00e4r m\u00f6jliga.", + "SmartSubtitlesHelp": "Undertexter som matchar f\u00f6rvalsspr\u00e5ket kommer visas n\u00e4r ljudsp\u00e5ret \u00e4r p\u00e5 ett annat spr\u00e5k.", + "HeaderSubtitleSettings": "Inst\u00e4llningar f\u00f6r undertexter", + "HeaderSubtitleAppearance": "Undertextutseende", + "OnlyForcedSubtitlesHelp": "Endast undertexter markerade som tvingande kommer att laddas.", + "AlwaysPlaySubtitlesHelp": "Undertexter p\u00e5 det \u00f6nskade spr\u00e5ket kommer att laddas oavsett ljudsp\u00e5rets spr\u00e5k.", + "NoSubtitlesHelp": "Undertexter kommer inte visas per standard. Det kan fortfarande s\u00e4ttas p\u00e5 manuellt under uppspelning.", + "LabelPreferredSubtitleLanguage": "\u00d6nskat spr\u00e5k f\u00f6r undertexter:", + "LabelTextSize": "Textstorlek:", + "TheseSettingsAffectSubtitlesOnThisDevice": "Dessa inst\u00e4llningar p\u00e5verkar undertexter p\u00e5 den h\u00e4r enheten", + "LabelDropShadow": "Visa skugga:", + "LabelTextBackgroundColor": "Bakgrundsf\u00e4rg f\u00f6r text:", + "LabelWindowBackgroundColor": "Bakgrundsf\u00e4rg f\u00f6r text:", + "LabelFont": "Typsnitt:", + "LabelTextColor": "Textf\u00e4rg:", + "Raised": "Upph\u00f6jd", + "Depressed": "Neds\u00e4nkt", + "Uniform": "Uniform", + "DropShadow": "Visa skugga", + "SmallCaps": "Sm\u00e5 bokst\u00e4ver", + "SubtitleAppearanceSettingsDisclaimer": "Dessa inst\u00e4llningar kommer inte g\u00e4lla f\u00f6r grafiska undertexter (PGS, DVD, etc), eller undertexter som har en egen inb\u00e4ddad stil (ASS\/SSA).", + "LabelBurnSubtitles": "Br\u00e4nn untertexter:", + "OnlyImageFormats": "Endast image-format (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Avg\u00f6r ifall servern ska \"br\u00e4nna in\" undertexterna under videokonverteringen, beroende p\u00e5 undertextsformatet. Att undvika inbr\u00e4nning av undertexter kommer att f\u00f6rb\u00e4ttra prestandan p\u00e5 servern. V\u00e4lj Auto f\u00f6r att br\u00e4nna image-baserade formats (ex. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA undertexter.", + "AllComplexFormats": "Alla komplexa format (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Dessa inst\u00e4llningar g\u00e4ller ocks\u00e5 f\u00f6r alla uppspelningar p\u00e5 Chromecast som startas av den h\u00e4r enheten.", + "HeaderWaitingForWifi": "V\u00e4ntar p\u00e5 Wifi", + "WifiRequiredToDownload": "En Wifi-anslutning kr\u00e4vs f\u00f6r att forts\u00e4tta nedladdningen.", + "HeaderDownloadSettings": "Nedladdningsinst\u00e4llningar", + "Hide": "D\u00f6lj", + "HeaderStartNow": "Starta nu", + "HeaderNextVideoPlayingInValue": "N\u00e4sta video b\u00f6rjar om {0}", + "HeaderNextEpisodePlayingInValue": "N\u00e4sta avsnitt b\u00f6rjar om {0}", + "HeaderSecondsValue": "{0} sekunder", + "AudioBitDepthNotSupported": "Ljudets bitdjup st\u00f6ds inte", + "VideoProfileNotSupported": "Videoprofilen st\u00f6ds inte", + "VideoFramerateNotSupported": "Videons framerate st\u00f6ds inte", + "VideoBitDepthNotSupported": "Videons bitdjup st\u00f6ds inte", + "RefFramesNotSupported": "Antal video reference frames som inte st\u00f6ds", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Avbryt inspelning", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Hantera inspelning", + "LabelDropImageHere": "Sl\u00e4pp en bild h\u00e4r, eller klicka f\u00f6r att bl\u00e4ddra.", + "MessageFileReadError": "Ett fel uppstod n\u00e4r filen l\u00e4stes in. Var god f\u00f6rs\u00f6k igen.", + "Browse": "Bl\u00e4ddra", + "HeaderUploadImage": "Ladda upp bild", + "HeaderAddUpdateImage": "L\u00e4gg till\/uppdatera bild", + "LabelImageType": "Typ av bild:", + "Upload": "Ladda upp", + "Primary": "Prim\u00e4r", + "Art": "Grafik", + "Backdrop": "Fondbild", + "Banner": "Banderoll", + "Box": "Omslag", + "BoxRear": "Omslag (baksida)", + "Disc": "Skiva", + "Logo": "Logotyp", + "Menu": "Meny", + "Screenshot": "Sk\u00e4rmdump", + "Thumb": "Miniatyr", + "ValueSeconds": "{0} sekunder", + "HeaderAudioSettings": "Ljudinst\u00e4llningar", + "LabelAudioLanguagePreference": "\u00d6nskat ljudspr\u00e5k:", + "LabelPlayDefaultAudioTrack": "Anv\u00e4nd det f\u00f6rvalda ljudsp\u00e5ret oavsett spr\u00e5k", + "HeaderVideoQuality": "Videokvalitet", + "CinemaModeConfigurationHelp": "Biol\u00e4get g\u00f6r ditt vardagsrum till en biograf genom m\u00f6jligheten att visa trailers och egna vinjetter innan filmen b\u00f6rjar.", + "EnableNextVideoInfoOverlay": "Visa info om n\u00e4sta video under uppspelning", + "EnableNextVideoInfoOverlayHelp": "Vid slutet av en video, visa information om n\u00e4stf\u00f6ljande video i spellistan.", + "PlayNextEpisodeAutomatically": "Spela n\u00e4sta avsnitt automatiskt", + "LabelMaxChromecastBitrate": "Str\u00f6mningskvalitet f\u00f6r Chromecast:", + "LabelSkipBackLength": "'Hoppa bak\u00e5t'-l\u00e4ngd:", + "LabelSkipForwardLength": "'Hoppa fram\u00e5t'-l\u00e4ngd:", + "EnableCinemaMode": "Aktivera biol\u00e4ge", + "LabelInternetQuality": "Internetkvalitet:", + "HeaderMusicQuality": "Musikkvalitet:", + "LabelHomeNetworkQuality": "Hemn\u00e4tverkskvalitet:", + "HeaderLatestMedia": "Nytillkommet", + "HeaderRestartingEmbyServer": "Startar om Emby-servern", + "RestartPleaseWaitMessage": "V\u00e4nligen v\u00e4nta medan Emby-servern st\u00e4ngs av och startar om. Detta kan ta en minut eller tv\u00e5.", + "PlayNext": "Spela n\u00e4sta", + "AllowSeasonalThemes": "Till\u00e5t automatiska s\u00e4songsbaserade teman", + "AllowSeasonalThemesHelp": "Om aktiverat kommer s\u00e4songsteman emellan\u00e5t kringg\u00e5 din temainst\u00e4llning.", + "AutoBasedOnLanguageSetting": "Automatisk (baserad p\u00e5 spr\u00e5kinst\u00e4llning)", + "LabelDateTimeLocale": "Spr\u00e5ktidsformat:", + "DirectorValue": "Regi: {0}", + "DirectorsValue": "Regi: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genrer: {0}", + "LinksValue": "L\u00e4nkar: {0}", + "TagsValue": "Etiketter: {0}", + "LabelAudio": "Ljud:", + "LabelVideo": "Video:", + "LabelSubtitles": "Undertexter:", + "Off": "Av", + "ShowTitle": "Visa titel", + "ShowYear": "Visa \u00e5r", + "Filters": "Filter", + "Unplayed": "Inte spelad", + "LabelTVHomeScreen": "Hemsk\u00e4rm i TV-l\u00e4ge:", + "Horizontal": "Horisontell", + "Vertical": "Vertikal", + "GroupBySeries": "Gruppera efter serie", + "HeaderVideoType": "Videotyp", + "HeaderSeriesStatus": "Seriestatus", + "Features": "Inneh\u00e5ll", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Vinjetter", + "ThemeVideos": "Temavideos", + "HeaderFavoriteMovies": "Favoritfilmer", + "HeaderFavoriteShows": "Favoritserier", + "HeaderFavoriteEpisodes": "Favoritavsnitt", + "HeaderFavoriteVideos": "Favoritvideos", + "HeaderFavoriteGames": "Favoritspel", + "HeaderFavoriteArtists": "Favoritartister", + "HeaderFavoriteAlbums": "Favoritalbum", + "HeaderFavoriteSongs": "Favoritl\u00e5tar", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/tr.json b/src/bower_components/emby-webcomponents/strings/tr.json index 5a4ff9a00c..1f6742fb1b 100644 --- a/src/bower_components/emby-webcomponents/strings/tr.json +++ b/src/bower_components/emby-webcomponents/strings/tr.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Ekle", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "Yeni", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "İptal", - "ButtonGotIt": "Got It", - "ButtonOk": "Tamam", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Tekrar Başlat", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Devam ediyor", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Günler", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Sil", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Düzenle", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Sonlandı", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Cuma", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Tarihi Seçin", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Ülke:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Dil:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "İsim:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Tür:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Yıl:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Canlı", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Pazartesi", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "Yeni Koleksiyon", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Ebeveyn değeri", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Oynat", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Kayıt", - "RecordSeries": "Record series", - "RecordingCancelled": "Kayıt iptal edildi.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Cumartesi", - "Save": "Kaydet", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Pazar", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Perşembe", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Salı", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Çarşamba", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Ekle", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "Yeni", + "Premiere": "Premiere", + "Live": "Canl\u0131", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Tarihi Se\u00e7in", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Tamam", + "ButtonCancel": "\u0130ptal", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Tekrar Ba\u015flat", + "RecordingCancelled": "Kay\u0131t iptal edildi.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Pazar", + "Monday": "Pazartesi", + "Tuesday": "Sal\u0131", + "Wednesday": "\u00c7ar\u015famba", + "Thursday": "Per\u015fembe", + "Friday": "Cuma", + "Saturday": "Cumartesi", + "Days": "G\u00fcnler", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Kay\u0131t", + "Save": "Kaydet", + "Edit": "D\u00fczenle", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Sil", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "Yeni Koleksiyon", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "\u0130sim:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Dil:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Oynat", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Y\u0131l:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "\u00dclke:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Devam ediyor", + "Ended": "Sonland\u0131", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Ebeveyn de\u011feri", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "T\u00fcr:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/uk.json b/src/bower_components/emby-webcomponents/strings/uk.json index dc598bb6bd..fb3b9afe5d 100644 --- a/src/bower_components/emby-webcomponents/strings/uk.json +++ b/src/bower_components/emby-webcomponents/strings/uk.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Add", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Скасувати", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Не подобається", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Улюблене", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friday", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Дата народження:", - "LabelBirthYear": "Рік народження:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Країна:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Дата смерті:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Мова:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Name:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Шлях:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Подобається", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Monday", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Saturday", - "Save": "Зберігти", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Налаштування", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Sunday", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Thursday", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tuesday", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} альбомів", - "ValueDiscNumber": "Диск {0}", - "ValueEpisodeCount": "{0} епізодів", - "ValueGameCount": "{0} ігр", - "ValueMinutes": "{0} хвилин", - "ValueMovieCount": "{0} фільмів", - "ValueMusicVideoCount": "{0} музичних кліпів", - "ValueOneAlbum": "1 альбом", - "ValueOneEpisode": "1 епізод", - "ValueOneGame": "1 гра", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 фільм", - "ValueOneMusicVideo": "1 музичний кліп", - "ValueOneSeries": "1 серія", - "ValueOneSong": "1 пісня", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} серій", - "ValueSongCount": "{0} пісень", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Wednesday", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Add", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "\u0421\u043a\u0430\u0441\u0443\u0432\u0430\u0442\u0438", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "\u0417\u0431\u0435\u0440\u0456\u0433\u0442\u0438", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "Name:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "\u041c\u043e\u0432\u0430:", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "\u0414\u0438\u0441\u043a {0}", + "Unrated": "Unrated", + "Favorite": "\u0423\u043b\u044e\u0431\u043b\u0435\u043d\u0435", + "Like": "\u041f\u043e\u0434\u043e\u0431\u0430\u0454\u0442\u044c\u0441\u044f", + "Dislike": "\u041d\u0435 \u043f\u043e\u0434\u043e\u0431\u0430\u0454\u0442\u044c\u0441\u044f", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "\u0428\u043b\u044f\u0445:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "\u041a\u0440\u0430\u0457\u043d\u0430:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "\u0420\u0456\u043a \u043d\u0430\u0440\u043e\u0434\u0436\u0435\u043d\u043d\u044f:", + "LabelBirthDate": "\u0414\u0430\u0442\u0430 \u043d\u0430\u0440\u043e\u0434\u0436\u0435\u043d\u043d\u044f:", + "LabelDeathDate": "\u0414\u0430\u0442\u0430 \u0441\u043c\u0435\u0440\u0442\u0456:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 \u043f\u0456\u0441\u043d\u044f", + "ValueSongCount": "{0} \u043f\u0456\u0441\u0435\u043d\u044c", + "ValueOneMovie": "1 \u0444\u0456\u043b\u044c\u043c", + "ValueMovieCount": "{0} \u0444\u0456\u043b\u044c\u043c\u0456\u0432", + "ValueOneSeries": "1 \u0441\u0435\u0440\u0456\u044f", + "ValueSeriesCount": "{0} \u0441\u0435\u0440\u0456\u0439", + "ValueOneEpisode": "1 \u0435\u043f\u0456\u0437\u043e\u0434", + "ValueEpisodeCount": "{0} \u0435\u043f\u0456\u0437\u043e\u0434\u0456\u0432", + "ValueOneGame": "1 \u0433\u0440\u0430", + "ValueGameCount": "{0} \u0456\u0433\u0440", + "ValueOneAlbum": "1 \u0430\u043b\u044c\u0431\u043e\u043c", + "ValueAlbumCount": "{0} \u0430\u043b\u044c\u0431\u043e\u043c\u0456\u0432", + "ValueOneMusicVideo": "1 \u043c\u0443\u0437\u0438\u0447\u043d\u0438\u0439 \u043a\u043b\u0456\u043f", + "ValueMusicVideoCount": "{0} \u043c\u0443\u0437\u0438\u0447\u043d\u0438\u0445 \u043a\u043b\u0456\u043f\u0456\u0432", + "ValueMinutes": "{0} \u0445\u0432\u0438\u043b\u0438\u043d", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "\u041d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/vi.json b/src/bower_components/emby-webcomponents/strings/vi.json index c695aed76f..d18888a4cb 100644 --- a/src/bower_components/emby-webcomponents/strings/vi.json +++ b/src/bower_components/emby-webcomponents/strings/vi.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "Thêm", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "Thoát", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "Continuing", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "Days", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "Delete", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "Edit", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "Ended", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "Friday", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "Select Date", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "Help", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "Quốc gia:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "Ngôn ngữ", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "Tên:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "Thứ Hai", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "New Collection", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "Example: Star Wars Collection", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "Play", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "Record", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "Refresh", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "Thứ Bảy", - "Save": "Lưu", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "Search for Subtitles", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "Chủ Nhật", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "Thursday", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "Tuesday", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "Wednesday", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "Th\u00eam", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "Select Date", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "Tho\u00e1t", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "Restart", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "Ch\u1ee7 Nh\u1eadt", + "Monday": "Th\u1ee9 Hai", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Th\u1ee9 B\u1ea3y", + "Days": "Days", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "Record", + "Save": "L\u01b0u", + "Edit": "Edit", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "Delete", + "HeaderDeleteItem": "Delete Item", + "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", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "New Collection", + "LabelCollection": "Collection:", + "Help": "Help", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "Search the internet for artwork and metadata", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "T\u00ean:", + "NewCollectionNameExample": "Example: Star Wars Collection", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "Search for Subtitles", + "LabelLanguage": "Ng\u00f4n ng\u1eef", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "Play", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "Qu\u1ed1c gia:", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "Continuing", + "Ended": "Ended", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/zh-cn.json b/src/bower_components/emby-webcomponents/strings/zh-cn.json index aae1569228..e792e30cc4 100644 --- a/src/bower_components/emby-webcomponents/strings/zh-cn.json +++ b/src/bower_components/emby-webcomponents/strings/zh-cn.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "接受", - "AccessRestrictedTryAgainLater": "访问目前受限。请稍后再试。", - "Actor": "演员", - "Add": "添加", - "AddToCollection": "加入收藏", - "AddToPlayQueue": "添加至播放队列", - "AddToPlaylist": "添加到播放列表", - "AddedOnValue": "已添加 {0}", - "Advanced": "高级", - "AirDate": "播出日期", - "Aired": "已发布", - "Albums": "专辑", - "All": "All", - "AllChannels": "所有频道", - "AllComplexFormats": "所有复杂的格式(ASS, SSA, VOBSUB, PGS, SUB/IDX 等)", - "AllEpisodes": "所有集", - "AllLanguages": "所有语言", - "AllowSeasonalThemes": "允许自动切换季节性主题", - "AllowSeasonalThemesHelp": "如果启用,当季节性主题使用时会覆盖你的主题设置。", - "AlwaysPlaySubtitles": "总是显示字幕", - "AlwaysPlaySubtitlesHelp": "无论音频为何种语言,都将加载与语言偏好匹配的字幕。", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "任何时间", - "AroundTime": "{0} 左右", - "Art": "Art", - "Artists": "艺术家", - "AsManyAsPossible": "尽可能多", - "Ascending": "升序", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "尝试唤醒服务器中,请耐心等待...", - "AttributeNew": "新增", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "音频比特率不受支持", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "音频编码不受支持", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "自动", - "AutoBasedOnLanguageSetting": "自动(取决于语言设置)", - "AutomaticallyConvertNewContent": "自动转换新内容", - "AutomaticallyConvertNewContentHelp": "添加到这个文件夹的新内容将会被自动转换。", - "AutomaticallySyncNewContent": "自动下载新内容", - "AutomaticallySyncNewContentHelp": "添加到这个文件夹的新内容将会被自动下载到设备上。", - "Backdrop": "背景", - "Backdrops": "背景", - "Banner": "横幅", - "BestFit": "Best fit", - "BirthLocation": "出生地", - "Books": "书籍", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "浏览", - "BurnSubtitlesHelp": "根据字幕格式确定服务器在转换视频时是否应烧录字幕。避免烧录字幕会提高服务器性能。选择“自动”以烧录基于图像的字幕格式(如 VOBSUB, PGS, SUB/IDX 等)和一些复杂的 ASS/SSA 字幕。", - "ButtonCancel": "取消", - "ButtonGotIt": "知道了", - "ButtonOk": "确定", - "ButtonPlayOneMinute": "播放一分钟", - "ButtonRestart": "重启", - "ButtonRestorePreviousPurchase": "恢复购买", - "ButtonTryAgain": "重试", - "ButtonUnlockPrice": "解锁 {0}", - "ButtonUnlockWithPurchase": "购买以解锁", - "CancelDownload": "取消下载", - "CancelRecording": "取消录制", - "CancelSeries": "取消系列", - "Categories": "分类", - "ChannelNameOnly": "只在频道 {0}", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "影院模式直接为您的客厅带来剧场级体验,同时还可以播放预告片和自定义介绍。", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "同步你的媒体到云以便于备份,存档和转换。", - "Collections": "收藏", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "公众评分", - "Composer": "作曲家", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "删除图片?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "确认删除", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "删除下载?", - "Connect": "连接", - "ContainerBitrateExceedsLimit": "媒体比特率超过限制。", - "ContainerNotSupported": "Container not supported", - "Continue": "继续", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "继续观看", - "Continuing": "继续", - "Convert": "转换", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "仅转换未观看的视频", - "ConvertUnwatchedVideosOnlyHelp": "只有未观看的视频会被转换。", - "ConvertingDots": "Converting...", - "Countries": "国家", - "CriticRating": "影评人评分", - "DateAdded": "加入日期", - "DatePlayed": "播放日期", - "Days": "天", - "Default": "默认", - "DefaultErrorMessage": "处理请求时发生错误。请稍后尝试。", - "DefaultSubtitlesHelp": "字幕将基于内嵌元数据中的“默认”标志和“强制”标志来载入。当多个选项可用时,将根据语言偏好决定。", - "Delete": "删除", - "DeleteMedia": "删除媒体", - "Depressed": "Depressed", - "Descending": "降序", - "Desktop": "桌面", - "DirectPlayError": "直接播放发生错误", - "DirectPlaying": "直接播放", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "直接串流一个文件仅仅会占用非常少的处理能力并且视频的品质不会有任何损失。", - "DirectStreaming": "直接串流", - "Director": "导演", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "光盘", - "Disconnect": "断开连接", - "Dislike": "不喜欢", - "Display": "显示", - "DisplayInMyMedia": "在主屏幕显示", - "DisplayInOtherHomeScreenSections": "在“最新的媒体”和“继续观看“等主屏幕模块中显示", - "DisplayMissingEpisodesWithinSeasons": "显示每季里缺少的剧集", - "DisplayMissingEpisodesWithinSeasonsHelp": "必须在 Jellyfin 服务器的 TV 媒体库设置中也启用该功能。", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "不录制", - "Down": "下", - "Download": "下载", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "已下载", - "Downloading": "下载中", - "DownloadingDots": "正在下载...", - "Downloads": "下载", - "DownloadsValue": "{0} 下载", - "DropShadow": "阴影", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "编辑", - "EditImages": "修改图片", - "EditMetadata": "编辑元数据", - "EditSubtitles": "修改字幕", - "EnableBackdrops": "启用背景图", - "EnableBackdropsHelp": "如果启用,当浏览媒体库时背景图将作为一些页面的背景显示。", - "EnableCinemaMode": "启用影院模式", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "开启显示镜像", - "EnableExternalVideoPlayers": "启用外部播放器", - "EnableExternalVideoPlayersHelp": "当你开始播放视频时,将会显示一个外部播放器菜单。", - "EnableNextVideoInfoOverlay": "在播放时启用下一个视频信息", - "EnableNextVideoInfoOverlayHelp": "在视频结尾处,显示当前播放列表中下一个视频的信息。", - "EnableThemeSongs": "启用主题曲", - "EnableThemeSongsHelp": "如果启用,当浏览媒体库时主题曲将作为背景音乐播放。", - "EnableThemeVideos": "启用主题视频", - "EnableThemeVideosHelp": "如果启用,当浏览媒体库时主题视频将作为背景视频播放。", - "Ended": "结束", - "EndsAtValue": "结束于 {0}", - "Episodes": "剧集", - "Error": "错误", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "特大", - "Extras": "额外", - "Favorite": "我的最爱", - "Favorites": "我的最爱", - "FeatureRequiresJellyfinPremiere": "这项功能需要一个有效的 Jellyfin Premiere 订阅。", - "Features": "Features", - "File": "文件", - "Fill": "Fill", - "Filters": "筛选", - "Folders": "文件夹", - "FormatValue": "格式:{0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "星期五", - "GenreValue": "Genre: {0}", - "Genres": "风格", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "特邀明星", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "高清节目", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "加入收藏", - "HeaderAddToPlaylist": "添加到播放列表", - "HeaderAddUpdateImage": "添加/更新 图片", - "HeaderAlbumArtists": "专辑艺术家", - "HeaderAlreadyPaid": "已付款?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "有声读物", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "获取 Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "影院模式", - "HeaderCloudSync": "云同步", - "HeaderConfirmRecordingCancellation": "确认取消录制", - "HeaderContinueListening": "继续听", - "HeaderContinueWatching": "继续观看", - "HeaderConvertYourRecordings": "转换您的录制", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "删除项目", - "HeaderDeleteItems": "删除项目", - "HeaderDisplaySettings": "显示设置", - "HeaderDownloadSettings": "下载设置", - "HeaderEditImages": "修改图片", - "HeaderEnabledFields": "已启用的栏", - "HeaderEnabledFieldsHelp": "反选栏以锁定并不让其数据被更改。", - "HeaderExternalIds": "外部 Ids:", - "HeaderFavoriteAlbums": "最爱的专辑", - "HeaderFavoriteArtists": "最爱的艺术家", - "HeaderFavoriteCollections": "最爱的收藏", - "HeaderFavoriteEpisodes": "最爱的剧集", - "HeaderFavoriteGames": "最爱的游戏", - "HeaderFavoriteMovies": "最爱的电影", - "HeaderFavoritePlaylists": "最爱的播放列表", - "HeaderFavoriteShows": "最爱的节目", - "HeaderFavoriteSongs": "最爱的歌曲", - "HeaderFavoriteVideos": "最爱的视频", - "HeaderFreeApps": "免费 Jellyfin 应用", - "HeaderHomeScreen": "主屏幕", - "HeaderIdentifyItemHelp": "输入一个或多个搜索条件。删除条件可得到更多搜索结果。", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin 账户已添加", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "最新频道项目", - "HeaderLatestChannelMedia": "最新频道项目", - "HeaderLatestFrom": "最新的 {0}", - "HeaderLatestMedia": "最新媒体", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "了解更多", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "媒体库顺序", - "HeaderMetadataSettings": "元数据设置", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "我的设备", - "HeaderMyDownloads": "我的下载", - "HeaderMyMedia": "我的媒体", - "HeaderMyMediaSmall": "我的媒体 (小)", - "HeaderNewRecording": "新录制", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "下一个", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "离线媒体", - "HeaderOfflineDownloadsDescription": "下载媒体到你的设备上以便于离线使用。", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "相册", - "HeaderPlayMyMedia": "播放我的媒体", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "播放错误", - "HeaderRecordingOptions": "录制选项", - "HeaderRemoteControl": "远程控制", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "请说些什么,比如...", - "HeaderSecondsValue": "{0} 秒", - "HeaderSelectDate": "选择日期", - "HeaderSeriesOptions": "系列选项", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "特别剧集信息", - "HeaderStartNow": "现在开始", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "字幕外观", - "HeaderSubtitleSettings": "字幕设置", - "HeaderSyncRequiresSub": "下载需要一个有效的 Jellyfin Premiere 订阅。", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "解锁功能", - "HeaderUploadImage": "上传图片", - "HeaderVideoQuality": "视频质量", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "等待 Wifi 连接", - "HeaderWakeServer": "唤醒服务器", - "HeaderYouSaid": "您说了...", - "Help": "帮助", - "Hide": "隐藏", - "HideWatchedContentFromLatestMedia": "从最新媒体中隐藏已观看的内容", - "Home": "首页", - "Horizontal": "Horizontal", - "HowDidYouPay": "你想如何付款?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "我已购买此应用", - "Identify": "识别", - "Images": "图片", - "ImdbRating": "IMDb 评分", - "InstallingPackage": "正在安装 {0}", - "InstantMix": "即时混音", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} 项", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "儿童", - "Label3DFormat": "3D格式:", - "LabelAirDays": "播出日期:", - "LabelAirTime": "播出时间:", - "LabelAirsAfterSeason": "季播出后:", - "LabelAirsBeforeEpisode": "集播出前:", - "LabelAirsBeforeSeason": "季播出前:", - "LabelAlbum": "专辑:", - "LabelAlbumArtists": "专辑作家:", - "LabelArtists": "艺术家:", - "LabelArtistsHelp": "独立多功能;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "首选音频语言:", - "LabelBirthDate": "出生日期:", - "LabelBirthYear": "出生年份:", - "LabelBitrateMbps": "比特率 (Mbps):", - "LabelBurnSubtitles": "烧录字幕:", - "LabelChannels": "频道:", - "LabelCollection": "收藏:", - "LabelCommunityRating": "公众评分:", - "LabelContentType": "内容类型", - "LabelConvertTo": "转换为:", - "LabelCountry": "国家:", - "LabelCriticRating": "影评人评分:", - "LabelCustomRating": "自定义分级:", - "LabelDashboardTheme": "控制台主题:", - "LabelDateAdded": "加入日期:", - "LabelDateTimeLocale": "时区设置:", - "LabelDeathDate": "去世日期:", - "LabelDefaultScreen": "默认分页:", - "LabelDiscNumber": "光盘号:", - "LabelDisplayLanguage": "显示的语言:", - "LabelDisplayLanguageHelp": "Jellyfin的翻译工作是一个不断推进的工程项目。", - "LabelDisplayMode": "显示模式:", - "LabelDisplayOrder": "显示顺序:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "阴影:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "邮箱地址:", - "LabelEndDate": "结束日期:", - "LabelEpisodeNumber": "集号:", - "LabelFont": "字体:", - "LabelHomeNetworkQuality": "家庭网络质量:", - "LabelHomeScreenSectionValue": "主屏幕模块{0}:", - "LabelImageType": "图片类型:", - "LabelInternetQuality": "网络质量:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "保留:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "语言:", - "LabelLockItemToPreventChanges": "锁定此项目防止改动", - "LabelMaxChromecastBitrate": "最大 Chromecast 比特率:", - "LabelMetadataDownloadLanguage": "首选下载语言:", - "LabelName": "名字:", - "LabelNumber": "编号:", - "LabelOriginalAspectRatio": "原始长宽比:", - "LabelOriginalTitle": "原标题:", - "LabelOverview": "内容概述:", - "LabelParentNumber": "父编号:", - "LabelParentalRating": "家长分级:", - "LabelPath": "路径:", - "LabelPersonRole": "角色:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "出生地:", - "LabelPlayDefaultAudioTrack": "播放默认音轨无论是什么语言", - "LabelPlaylist": "播放列表:", - "LabelPreferredSubtitleLanguage": "字幕语言偏好:", - "LabelProfile": "配置:", - "LabelQuality": "质量:", - "LabelReasonForTranscoding": "转码的原因:", - "LabelRecord": "录制:", - "LabelRefreshMode": "刷新模式:", - "LabelReleaseDate": "发行日期:", - "LabelRuntimeMinutes": "播放时长(分钟):", - "LabelScreensaver": "屏幕保护:", - "LabelSeasonNumber": "季号:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "简介:", - "LabelSkin": "皮肤:", - "LabelSkipBackLength": "跳过长度:", - "LabelSkipForwardLength": "快进长度", - "LabelSortBy": "排序方式", - "LabelSortOrder": "排序顺序", - "LabelSortTitle": "短标题:", - "LabelSoundEffects": "音效:", - "LabelSource": "来源:", - "LabelStartWhenPossible": "当可能时自动开始:", - "LabelStatus": "状态:", - "LabelStopWhenPossible": "当可能时自动停止:", - "LabelSubtitlePlaybackMode": "字幕模式:", - "LabelSubtitles": "字幕:", - "LabelSyncJobName": "同步任务名称:", - "LabelSyncNoTargetsHelp": "看起来您目前还没有任何应用程序支持离线下载。", - "LabelSyncTo": "同步到:", - "LabelTVHomeScreen": "TV 模式主屏幕:", - "LabelTagline": "口号:", - "LabelTextBackgroundColor": "文本背景色:", - "LabelTextColor": "文本颜色:", - "LabelTextSize": "文本大小:", - "LabelTheme": "主题:", - "LabelTitle": "标题:", - "LabelTrackNumber": "音轨号码:", - "LabelType": "类型:", - "LabelVersion": "版本:", - "LabelVideo": "Video:", - "LabelWebsite": "网站:", - "LabelWindowBackgroundColor": "文本背景色:", - "LabelYear": "年份:", - "Large": "大", - "LatestFromLibrary": "最新的{0}", - "LearnHowYouCanContribute": "学习如何构建。", - "LearnMore": "了解更多", - "Like": "喜欢", - "LinksValue": "Links: {0}", - "List": "列表", - "Live": "直播", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "通过一个安装在你的 Jellyfin 服务器上的受兼容的电视协调器来串流你的电视直播至任何其他 Jellyfin 应用程序。", - "LiveTvRequiresUnlock": "电视直播需要一个有效的 Jellyfin Premiere 订阅。", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "标为已播放", - "MarkUnplayed": "标为未播放", - "MarkWatched": "标记为已观看", - "MediaIsBeingConverted": "媒体正在被转换成与正在播放该媒体的设备兼容的格式。", - "Medium": "标准", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "你确定希望删除此字幕文件?", - "MessageConfirmRecordingCancellation": "取消录制?", - "MessageDownloadQueued": "下载已列队。", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "项目已保存。", - "MessageItemsAdded": "项目已添加。", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "留空则继承父项或全局默认值设置。", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "如果你已经拥有一个有效的 Jellyfin Premiere 订阅,请确保你已经在你 Jellyfin 服务器控制台的“Jellyfin Premiere”选项中配置了你的 Jellyfin Premiere,你可以在 Jellyfin 服务器控制台主菜单中找到“Jellyfin Premiere”选项。", - "MessageUnlockAppWithPurchaseOrSupporter": "通过一次性付费或一个有效的 Jellyfin Premiere 订阅来解锁这项功能。", - "MessageUnlockAppWithSupporter": "通过一个有效的 Jellyfin Premiere 订阅来解锁这项功能。", - "MessageWeDidntRecognizeCommand": "很抱歉,我们无法识别这个指令。", - "MinutesAfter": "分钟后", - "MinutesBefore": "分钟前", - "Mobile": "手机/平板", - "Monday": "星期一", - "More": "更多", - "MoveLeft": "左移", - "MoveRight": "右移", - "Movies": "电影", - "MySubtitles": "我的字幕", - "Name": "名称", - "NewCollection": "新收藏", - "NewCollectionHelp": "“收藏”允许你为电影和其他媒体库内容创建个性化分组。", - "NewCollectionNameExample": "例如:星球大战收藏", - "NewEpisodes": "新剧集", - "NewEpisodesOnly": "只新集", - "News": "新闻", - "Next": "下一个", - "No": "否", - "NoItemsFound": "未找到项目。", - "NoSubtitleSearchResultsFound": "未找到结果。", - "NoSubtitles": "无字幕", - "NoSubtitlesHelp": "字幕将默认不被加载,但你仍然可以在播放时手动打开字幕。", - "None": "无", - "Normal": "普通", - "Off": "Off", - "OneChannel": "一个频道", - "OnlyForcedSubtitles": "只显示强制字幕", - "OnlyForcedSubtitlesHelp": "只有被标记为“强制”的字幕会被加载。", - "OnlyImageFormats": "仅图像格式(VOBSUB, PGS, SUB/IDX 等)", - "Open": "打开", - "OptionNew": "更新...", - "Original": "原始的", - "OriginalAirDateValue": "首映日期:{0}", - "Overview": "概述", - "PackageInstallCancelled": "{0} 安装被取消。", - "PackageInstallCompleted": "{0} 安装完成。", - "PackageInstallFailed": "{0} 安装失败。", - "ParentalRating": "家长分级", - "People": "人物", - "PerfectMatch": "最佳匹配", - "Photos": "照片", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "播放", - "PlayAllFromHere": "这里的全部内容都开始播放", - "PlayCount": "播放次数", - "PlayFromBeginning": "从头播放", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "请插入光盘以播放此视频。", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "已播放", - "Playlists": "播放列表", - "PleaseEnterNameOrId": "请输入一个名称或一个外部ID。", - "PleaseRestartServerName": "请重启 Jellyfin 服务器 - {0}。", - "PleaseSelectDeviceToSyncTo": "请选择要下载的设备。", - "PleaseSelectTwoItems": "请至少选择2个项目。", - "Premiere": "首映", - "Premieres": "Premieres", - "Previous": "上一个", - "Primary": "封面图", - "PrivacyPolicy": "Privacy policy", - "Producer": "制片人", - "ProductionLocations": "产地", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "质量", - "QueueAllFromHere": "这里的全部内容都加入队列", - "Raised": "Raised", - "RecentlyWatched": "最近观看", - "Record": "录制", - "RecordSeries": "录制电视剧", - "RecordingCancelled": "录制已取消。", - "RecordingScheduled": "录制计划", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "刷新", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "刷新元数据", - "RefreshQueued": "列队已刷新。", - "Reject": "拒绝", - "ReleaseDate": "发行日期", - "RemoveDownload": "移除下载", - "RemoveFromCollection": "从收藏中移除", - "RemoveFromPlaylist": "从播放列表中移除", - "RemovingFromDevice": "从设备移除中", - "Repeat": "重播", - "RepeatAll": "全部循环", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "循环模式", - "RepeatOne": "单项循环", - "ReplaceAllMetadata": "覆盖所有元数据", - "ReplaceExistingImages": "替换现有图片", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "恢复播放于{0}", - "Retry": "重试", - "RunAtStartup": "开机时启动", - "Runtime": "播放时长", - "Saturday": "星期六", - "Save": "储存", - "ScanForNewAndUpdatedFiles": "扫描新的和有修改的文件", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "截图", - "Search": "搜索", - "SearchForCollectionInternetMetadata": "在互联网上搜索媒体图像和资料", - "SearchForMissingMetadata": "搜索缺少的元数据", - "SearchForSubtitles": "搜索字幕", - "SearchResults": "搜索结果", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "电视剧已取消", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "电视剧录制计划", - "SeriesSettings": "系列设定", - "SeriesYearToPresent": "{0} - 现在", - "ServerNameIsRestarting": "Jellyfin Server - {0} 重启中。", - "ServerNameIsShuttingDown": "Jellyfin 服务器 - {0} 正在关闭。", - "ServerUpdateNeeded": "Jellyfin 服务器需要更新,请访问 {0} 以下载最新的版本。", - "Settings": "设置", - "SettingsSaved": "设置已保存。", - "Share": "共享", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "显示标题", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "随机播放", - "SkipEpisodesAlreadyInMyLibrary": "不录制我的媒体库里已存在的剧集", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "小", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "智能模式", - "SmartSubtitlesHelp": "当音频为外语时,将加载与语言偏好匹配的字幕。", - "Songs": "歌曲", - "Sort": "排序", - "SortByValue": "排序方式:{0}", - "SortChannelsBy": "频道排序方式:", - "SortName": "排序名称", - "Sports": "体育", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "工作室", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "这些设定也会被应用于任何通过此设备发起的 Chromecast 播放。", - "SubtitleAppearanceSettingsDisclaimer": "这些设置将不会应用于图形字幕(如 PGS,DVD 等),或者一些有着自己的内置式样的字幕(ASS/SSA)。", - "SubtitleCodecNotSupported": "字幕格式不被支持", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "字幕", - "Suggestions": "建议", - "Sunday": "星期天", - "Sync": "同步", - "SyncJobItemStatusCancelled": "已取消", - "SyncJobItemStatusConverting": "转换中", - "SyncJobItemStatusFailed": "已失败", - "SyncJobItemStatusQueued": "已列队", - "SyncJobItemStatusReadyToTransfer": "传输就绪", - "SyncJobItemStatusRemovedFromDevice": "已从设备移除", - "SyncJobItemStatusSynced": "已下载", - "SyncJobItemStatusSyncedMarkForRemoval": "从设备移除中", - "SyncJobItemStatusTransferring": "传输中", - "SyncUnwatchedVideosOnly": "仅下载未观看的视频", - "SyncUnwatchedVideosOnlyHelp": "只有未观看的视频会被下载,并且已经观看过的视频会从该设备上移除。", - "SyncingDots": "Syncing...", - "TV": "电视", - "Tags": "标签", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "主题曲", - "ThemeVideos": "主题视频", - "TheseSettingsAffectSubtitlesOnThisDevice": "这些设置仅影响该设备的字幕显示", - "Thumb": "缩略图", - "Thursday": "星期四", - "TrackCount": "{0} 个音轨", - "Trailer": "预告片", - "Trailers": "预告片", - "Transcoding": "转码", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "星期二", - "Uniform": "Uniform", - "UnlockGuide": "解锁指南", - "Unplayed": "未播放", - "Unrated": "未分级", - "UntilIDelete": "直到我删除", - "UntilSpaceNeeded": "直到需要空间", - "Up": "上", - "Upload": "上传", - "ValueAlbumCount": "{0} 张专辑", - "ValueDiscNumber": "盘 {0}", - "ValueEpisodeCount": "{0} 集", - "ValueGameCount": "{0} 个游戏", - "ValueMinutes": "{0} 分钟", - "ValueMovieCount": "{0} 个电影", - "ValueMusicVideoCount": "{0} 个音乐视频", - "ValueOneAlbum": "1张专辑", - "ValueOneEpisode": "1 集", - "ValueOneGame": "1 个游戏", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 个电影", - "ValueOneMusicVideo": "1个音乐视频", - "ValueOneSeries": "1 个系列", - "ValueOneSong": "1首歌", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} 个系列", - "ValueSongCount": "{0} 首歌", - "ValueSpecialEpisodeName": "特典 - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "视频编码不受支持", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "查看专辑", - "ViewArtist": "查看艺术家", - "VoiceInput": "语音输入", - "WakeServer": "唤醒服务器", - "WakeServerError": "Wake On LAN 数据包已经发送到你的服务器所在机器上,但我们不能连接到你的 Jellyfin 服务器。你的机器可能还需要一些时间才能被唤醒,或者\n Jellyfin 服务器没有正确的在机器上启动。", - "WakeServerSuccess": "成功!", - "Watched": "已观看", - "Wednesday": "星期三", - "WifiRequiredToDownload": "需要连接 Wifi 才能继续下载。", - "Writer": "编剧", - "Yes": "是" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "MessageUnlockAppWithPurchaseOrSupporter": "\u901a\u8fc7\u4e00\u6b21\u6027\u4ed8\u8d39\u6216\u4e00\u4e2a\u6709\u6548\u7684 Emby Premiere \u8ba2\u9605\u6765\u89e3\u9501\u8fd9\u9879\u529f\u80fd\u3002", + "MessageUnlockAppWithSupporter": "\u901a\u8fc7\u4e00\u4e2a\u6709\u6548\u7684 Emby Premiere \u8ba2\u9605\u6765\u89e3\u9501\u8fd9\u9879\u529f\u80fd\u3002", + "MessageToValidateSupporter": "\u5982\u679c\u4f60\u5df2\u7ecf\u62e5\u6709\u4e00\u4e2a\u6709\u6548\u7684 Emby Premiere \u8ba2\u9605\uff0c\u8bf7\u786e\u4fdd\u4f60\u5df2\u7ecf\u5728\u4f60 Emby \u670d\u52a1\u5668\u63a7\u5236\u53f0\u7684\u201cEmby Premiere\u201d\u9009\u9879\u4e2d\u914d\u7f6e\u4e86\u4f60\u7684 Emby Premiere\uff0c\u4f60\u53ef\u4ee5\u5728 Emby \u670d\u52a1\u5668\u63a7\u5236\u53f0\u4e3b\u83dc\u5355\u4e2d\u627e\u5230\u201cEmby Premiere\u201d\u9009\u9879\u3002", + "ValueSpecialEpisodeName": "\u7279\u5178 - {0}", + "Share": "\u5171\u4eab", + "Add": "\u6dfb\u52a0", + "ServerUpdateNeeded": "Emby \u670d\u52a1\u5668\u9700\u8981\u66f4\u65b0\uff0c\u8bf7\u8bbf\u95ee {0} \u4ee5\u4e0b\u8f7d\u6700\u65b0\u7684\u7248\u672c\u3002", + "LiveTvRequiresUnlock": "\u7535\u89c6\u76f4\u64ad\u9700\u8981\u4e00\u4e2a\u6709\u6548\u7684 Emby Premiere \u8ba2\u9605\u3002", + "AttributeNew": "\u65b0\u589e", + "Premiere": "\u9996\u6620", + "Live": "\u76f4\u64ad", + "Repeat": "\u91cd\u64ad", + "TrackCount": "{0} \u4e2a\u97f3\u8f68", + "ItemCount": "{0} \u9879", + "OriginalAirDateValue": "\u9996\u6620\u65e5\u671f\uff1a{0}", + "EndsAtValue": "\u7ed3\u675f\u4e8e {0}", + "HeaderSelectDate": "\u9009\u62e9\u65e5\u671f", + "Watched": "\u5df2\u89c2\u770b", + "AirDate": "\u64ad\u51fa\u65e5\u671f", + "Played": "\u5df2\u64ad\u653e", + "ButtonOk": "\u786e\u5b9a", + "ButtonCancel": "\u53d6\u6d88", + "AccessRestrictedTryAgainLater": "\u8bbf\u95ee\u76ee\u524d\u53d7\u9650\u3002\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002", + "ButtonGotIt": "\u77e5\u9053\u4e86", + "ButtonRestart": "\u91cd\u542f", + "RecordingCancelled": "\u5f55\u5236\u5df2\u53d6\u6d88\u3002", + "SeriesCancelled": "\u7535\u89c6\u5267\u5df2\u53d6\u6d88", + "RecordingScheduled": "\u5f55\u5236\u8ba1\u5212", + "SeriesRecordingScheduled": "\u7535\u89c6\u5267\u5f55\u5236\u8ba1\u5212", + "HeaderNewRecording": "\u65b0\u5f55\u5236", + "WakeServer": "\u5524\u9192\u670d\u52a1\u5668", + "HeaderWakeServer": "\u5524\u9192\u670d\u52a1\u5668", + "AttemptingWakeServer": "\u5c1d\u8bd5\u5524\u9192\u670d\u52a1\u5668\u4e2d\uff0c\u8bf7\u8010\u5fc3\u7b49\u5f85...", + "WakeServerSuccess": "\u6210\u529f\uff01", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN \u6570\u636e\u5305\u5df2\u7ecf\u53d1\u9001\u5230\u4f60\u7684\u670d\u52a1\u5668\u6240\u5728\u673a\u5668\u4e0a\uff0c\u4f46\u6211\u4eec\u4e0d\u80fd\u8fde\u63a5\u5230\u4f60\u7684 Emby \u670d\u52a1\u5668\u3002\u4f60\u7684\u673a\u5668\u53ef\u80fd\u8fd8\u9700\u8981\u4e00\u4e9b\u65f6\u95f4\u624d\u80fd\u88ab\u5524\u9192\uff0c\u6216\u8005\n Emby \u670d\u52a1\u5668\u6ca1\u6709\u6b63\u786e\u7684\u5728\u673a\u5668\u4e0a\u542f\u52a8\u3002", + "Sunday": "\u661f\u671f\u5929", + "Monday": "\u661f\u671f\u4e00", + "Tuesday": "\u661f\u671f\u4e8c", + "Wednesday": "\u661f\u671f\u4e09", + "Thursday": "\u661f\u671f\u56db", + "Friday": "\u661f\u671f\u4e94", + "Saturday": "\u661f\u671f\u516d", + "Days": "\u5929", + "SortByValue": "\u6392\u5e8f\u65b9\u5f0f\uff1a{0}", + "LabelSortBy": "\u6392\u5e8f\u65b9\u5f0f", + "LabelSortOrder": "\u6392\u5e8f\u987a\u5e8f", + "HeaderPhotoAlbums": "\u76f8\u518c", + "Photos": "\u7167\u7247", + "HeaderAppearsOn": "Appears On", + "List": "\u5217\u8868", + "RecordSeries": "\u5f55\u5236\u7535\u89c6\u5267", + "HeaderCinemaMode": "\u5f71\u9662\u6a21\u5f0f", + "HeaderCloudSync": "\u4e91\u540c\u6b65", + "Downloads": "\u4e0b\u8f7d", + "HeaderMyDownloads": "\u6211\u7684\u4e0b\u8f7d", + "HeaderOfflineDownloads": "\u79bb\u7ebf\u5a92\u4f53", + "HeaderOfflineDownloadsDescription": "\u4e0b\u8f7d\u5a92\u4f53\u5230\u4f60\u7684\u8bbe\u5907\u4e0a\u4ee5\u4fbf\u4e8e\u79bb\u7ebf\u4f7f\u7528\u3002", + "CloudSyncFeatureDescription": "\u540c\u6b65\u4f60\u7684\u5a92\u4f53\u5230\u4e91\u4ee5\u4fbf\u4e8e\u5907\u4efd\uff0c\u5b58\u6863\u548c\u8f6c\u6362\u3002", + "LiveTvFeatureDescription": "\u901a\u8fc7\u4e00\u4e2a\u5b89\u88c5\u5728\u4f60\u7684 Emby \u670d\u52a1\u5668\u4e0a\u7684\u53d7\u517c\u5bb9\u7684\u7535\u89c6\u534f\u8c03\u5668\u6765\u4e32\u6d41\u4f60\u7684\u7535\u89c6\u76f4\u64ad\u81f3\u4efb\u4f55\u5176\u4ed6 Emby \u5e94\u7528\u7a0b\u5e8f\u3002", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", + "HeaderFreeApps": "\u514d\u8d39 Emby \u5e94\u7528", + "FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.", + "HeaderBecomeProjectSupporter": "\u83b7\u53d6 Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "LabelEmailAddress": "\u90ae\u7bb1\u5730\u5740\uff1a", + "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": "\u8fd9\u9879\u529f\u80fd\u9700\u8981\u4e00\u4e2a\u6709\u6548\u7684 Emby Premiere \u8ba2\u9605\u3002", + "HeaderConvertYourRecordings": "\u8f6c\u6362\u60a8\u7684\u5f55\u5236", + "Record": "\u5f55\u5236", + "Save": "\u50a8\u5b58", + "Edit": "\u7f16\u8f91", + "Download": "\u4e0b\u8f7d", + "Downloaded": "\u5df2\u4e0b\u8f7d", + "Downloading": "\u4e0b\u8f7d\u4e2d", + "Advanced": "\u9ad8\u7ea7", + "Delete": "\u5220\u9664", + "HeaderDeleteItem": "\u5220\u9664\u9879\u76ee", + "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", + "Refresh": "\u5237\u65b0", + "RefreshQueued": "\u5217\u961f\u5df2\u5237\u65b0\u3002", + "AddToCollection": "\u52a0\u5165\u6536\u85cf", + "HeaderAddToCollection": "\u52a0\u5165\u6536\u85cf", + "NewCollection": "\u65b0\u6536\u85cf", + "LabelCollection": "\u6536\u85cf\uff1a", + "Help": "\u5e2e\u52a9", + "LabelDisplayMode": "\u663e\u793a\u6a21\u5f0f\uff1a", + "Desktop": "\u684c\u9762", + "Mobile": "\u624b\u673a\/\u5e73\u677f", + "TV": "\u7535\u89c6", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "\u663e\u793a\u7684\u8bed\u8a00\uff1a", + "LabelDisplayLanguageHelp": "Emby\u7684\u7ffb\u8bd1\u5de5\u4f5c\u662f\u4e00\u4e2a\u4e0d\u65ad\u63a8\u8fdb\u7684\u5de5\u7a0b\u9879\u76ee\u3002", + "LearnHowYouCanContribute": "\u5b66\u4e60\u5982\u4f55\u6784\u5efa\u3002", + "NewCollectionHelp": "\u201c\u6536\u85cf\u201d\u5141\u8bb8\u4f60\u4e3a\u7535\u5f71\u548c\u5176\u4ed6\u5a92\u4f53\u5e93\u5185\u5bb9\u521b\u5efa\u4e2a\u6027\u5316\u5206\u7ec4\u3002", + "SearchForCollectionInternetMetadata": "\u5728\u4e92\u8054\u7f51\u4e0a\u641c\u7d22\u5a92\u4f53\u56fe\u50cf\u548c\u8d44\u6599", + "DisplayMissingEpisodesWithinSeasons": "\u663e\u793a\u6bcf\u5b63\u91cc\u7f3a\u5c11\u7684\u5267\u96c6", + "DisplayMissingEpisodesWithinSeasonsHelp": "\u5fc5\u987b\u5728 Emby \u670d\u52a1\u5668\u7684 TV \u5a92\u4f53\u5e93\u8bbe\u7f6e\u4e2d\u4e5f\u542f\u7528\u8be5\u529f\u80fd\u3002", + "EnableThemeSongs": "\u542f\u7528\u4e3b\u9898\u66f2", + "EnableBackdrops": "\u542f\u7528\u80cc\u666f\u56fe", + "EnableThemeSongsHelp": "\u5982\u679c\u542f\u7528\uff0c\u5f53\u6d4f\u89c8\u5a92\u4f53\u5e93\u65f6\u4e3b\u9898\u66f2\u5c06\u4f5c\u4e3a\u80cc\u666f\u97f3\u4e50\u64ad\u653e\u3002", + "EnableBackdropsHelp": "\u5982\u679c\u542f\u7528\uff0c\u5f53\u6d4f\u89c8\u5a92\u4f53\u5e93\u65f6\u80cc\u666f\u56fe\u5c06\u4f5c\u4e3a\u4e00\u4e9b\u9875\u9762\u7684\u80cc\u666f\u663e\u793a\u3002", + "EnableThemeVideos": "\u542f\u7528\u4e3b\u9898\u89c6\u9891", + "EnableThemeVideosHelp": "\u5982\u679c\u542f\u7528\uff0c\u5f53\u6d4f\u89c8\u5a92\u4f53\u5e93\u65f6\u4e3b\u9898\u89c6\u9891\u5c06\u4f5c\u4e3a\u80cc\u666f\u89c6\u9891\u64ad\u653e\u3002", + "RunAtStartup": "\u5f00\u673a\u65f6\u542f\u52a8", + "LabelScreensaver": "\u5c4f\u5e55\u4fdd\u62a4\uff1a", + "LabelSoundEffects": "\u97f3\u6548\uff1a", + "LabelSkin": "\u76ae\u80a4\uff1a", + "LabelName": "\u540d\u5b57\uff1a", + "NewCollectionNameExample": "\u4f8b\u5982\uff1a\u661f\u7403\u5927\u6218\u6536\u85cf", + "MessageItemsAdded": "\u9879\u76ee\u5df2\u6dfb\u52a0\u3002", + "OptionNew": "\u66f4\u65b0...", + "LabelPlaylist": "\u64ad\u653e\u5217\u8868\uff1a", + "AddToPlaylist": "\u6dfb\u52a0\u5230\u64ad\u653e\u5217\u8868", + "HeaderAddToPlaylist": "\u6dfb\u52a0\u5230\u64ad\u653e\u5217\u8868", + "Subtitles": "\u5b57\u5e55", + "LabelTheme": "\u4e3b\u9898\uff1a", + "LabelDashboardTheme": "\u63a7\u5236\u53f0\u4e3b\u9898\uff1a", + "SearchForSubtitles": "\u641c\u7d22\u5b57\u5e55", + "LabelLanguage": "\u8bed\u8a00\uff1a", + "Search": "\u641c\u7d22", + "NoSubtitleSearchResultsFound": "\u672a\u627e\u5230\u7ed3\u679c\u3002", + "File": "\u6587\u4ef6", + "MessageAreYouSureDeleteSubtitles": "\u4f60\u786e\u5b9a\u5e0c\u671b\u5220\u9664\u6b64\u5b57\u5e55\u6587\u4ef6\uff1f", + "ConfirmDeletion": "\u786e\u8ba4\u5220\u9664", + "MySubtitles": "\u6211\u7684\u5b57\u5e55", + "MessageDownloadQueued": "\u4e0b\u8f7d\u5df2\u5217\u961f\u3002", + "EditSubtitles": "\u4fee\u6539\u5b57\u5e55", + "UnlockGuide": "\u89e3\u9501\u6307\u5357", + "RefreshMetadata": "\u5237\u65b0\u5143\u6570\u636e", + "ReplaceExistingImages": "\u66ff\u6362\u73b0\u6709\u56fe\u7247", + "ReplaceAllMetadata": "\u8986\u76d6\u6240\u6709\u5143\u6570\u636e", + "SearchForMissingMetadata": "\u641c\u7d22\u7f3a\u5c11\u7684\u5143\u6570\u636e", + "LabelRefreshMode": "\u5237\u65b0\u6a21\u5f0f\uff1a", + "NoItemsFound": "\u672a\u627e\u5230\u9879\u76ee\u3002", + "HeaderSaySomethingLike": "\u8bf7\u8bf4\u4e9b\u4ec0\u4e48\uff0c\u6bd4\u5982...", + "ButtonTryAgain": "\u91cd\u8bd5", + "HeaderYouSaid": "\u60a8\u8bf4\u4e86...", + "MessageWeDidntRecognizeCommand": "\u5f88\u62b1\u6b49\uff0c\u6211\u4eec\u65e0\u6cd5\u8bc6\u522b\u8fd9\u4e2a\u6307\u4ee4\u3002", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "\u76d8 {0}", + "Unrated": "\u672a\u5206\u7ea7", + "Favorite": "\u6211\u7684\u6700\u7231", + "Like": "\u559c\u6b22", + "Dislike": "\u4e0d\u559c\u6b22", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "\u6253\u5f00", + "Play": "\u64ad\u653e", + "AddToPlayQueue": "\u6dfb\u52a0\u81f3\u64ad\u653e\u961f\u5217", + "Shuffle": "\u968f\u673a\u64ad\u653e", + "Identify": "\u8bc6\u522b", + "EditImages": "\u4fee\u6539\u56fe\u7247", + "EditMetadata": "\u7f16\u8f91\u5143\u6570\u636e", + "Convert": "\u8f6c\u6362", + "Sync": "\u540c\u6b65", + "InstantMix": "\u5373\u65f6\u6df7\u97f3", + "ViewAlbum": "\u67e5\u770b\u4e13\u8f91", + "ViewArtist": "\u67e5\u770b\u827a\u672f\u5bb6", + "QueueAllFromHere": "\u8fd9\u91cc\u7684\u5168\u90e8\u5185\u5bb9\u90fd\u52a0\u5165\u961f\u5217", + "PlayAllFromHere": "\u8fd9\u91cc\u7684\u5168\u90e8\u5185\u5bb9\u90fd\u5f00\u59cb\u64ad\u653e", + "PlayFromBeginning": "\u4ece\u5934\u64ad\u653e", + "ResumeAt": "\u6062\u590d\u64ad\u653e\u4e8e{0}", + "RemoveFromPlaylist": "\u4ece\u64ad\u653e\u5217\u8868\u4e2d\u79fb\u9664", + "RemoveFromCollection": "\u4ece\u6536\u85cf\u4e2d\u79fb\u9664", + "Sort": "\u6392\u5e8f", + "Trailer": "\u9884\u544a\u7247", + "MarkPlayed": "\u6807\u4e3a\u5df2\u64ad\u653e", + "MarkUnplayed": "\u6807\u4e3a\u672a\u64ad\u653e", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "\u8bf7\u81f3\u5c11\u9009\u62e92\u4e2a\u9879\u76ee\u3002", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "\u786e\u8ba4\u53d6\u6d88\u5f55\u5236", + "MessageConfirmRecordingCancellation": "\u53d6\u6d88\u5f55\u5236\uff1f", + "Error": "\u9519\u8bef", + "VoiceInput": "\u8bed\u97f3\u8f93\u5165", + "LabelContentType": "\u5185\u5bb9\u7c7b\u578b", + "LabelPath": "\u8def\u5f84\uff1a", + "Playlists": "\u64ad\u653e\u5217\u8868", + "LabelTitle": "\u6807\u9898\uff1a", + "LabelOriginalTitle": "\u539f\u6807\u9898\uff1a", + "LabelSortTitle": "\u77ed\u6807\u9898\uff1a", + "LabelDateAdded": "\u52a0\u5165\u65e5\u671f\uff1a", + "DateAdded": "\u52a0\u5165\u65e5\u671f", + "DatePlayed": "\u64ad\u653e\u65e5\u671f", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "\u72b6\u6001\uff1a", + "LabelArtists": "\u827a\u672f\u5bb6\uff1a", + "LabelArtistsHelp": "\u72ec\u7acb\u591a\u529f\u80fd\uff1b", + "HeaderAlbumArtists": "\u4e13\u8f91\u827a\u672f\u5bb6", + "LabelAlbumArtists": "\u4e13\u8f91\u4f5c\u5bb6\uff1a", + "LabelAlbum": "\u4e13\u8f91\uff1a", + "Artists": "\u827a\u672f\u5bb6", + "ImdbRating": "IMDb \u8bc4\u5206", + "CommunityRating": "\u516c\u4f17\u8bc4\u5206", + "LabelCommunityRating": "\u516c\u4f17\u8bc4\u5206\uff1a", + "LabelCriticRating": "\u5f71\u8bc4\u4eba\u8bc4\u5206\uff1a", + "CriticRating": "\u5f71\u8bc4\u4eba\u8bc4\u5206", + "LabelWebsite": "\u7f51\u7ad9\uff1a", + "LabelTagline": "\u53e3\u53f7\uff1a", + "LabelOverview": "\u5185\u5bb9\u6982\u8ff0\uff1a", + "LabelShortOverview": "\u7b80\u4ecb\uff1a", + "LabelReleaseDate": "\u53d1\u884c\u65e5\u671f\uff1a", + "LabelYear": "\u5e74\u4efd\uff1a", + "LabelPlaceOfBirth": "\u51fa\u751f\u5730\uff1a", + "Aired": "\u5df2\u53d1\u5e03", + "LabelAirDays": "\u64ad\u51fa\u65e5\u671f\uff1a", + "LabelAirTime": "\u64ad\u51fa\u65f6\u95f4\uff1a", + "LabelRuntimeMinutes": "\u64ad\u653e\u65f6\u957f\uff08\u5206\u949f\uff09\uff1a", + "LabelParentalRating": "\u5bb6\u957f\u5206\u7ea7\uff1a", + "LabelCustomRating": "\u81ea\u5b9a\u4e49\u5206\u7ea7\uff1a", + "LabelOriginalAspectRatio": "\u539f\u59cb\u957f\u5bbd\u6bd4\uff1a", + "Label3DFormat": "3D\u683c\u5f0f\uff1a", + "FormatValue": "\u683c\u5f0f\uff1a{0}", + "DownloadsValue": "{0} \u4e0b\u8f7d", + "PerfectMatch": "\u6700\u4f73\u5339\u914d", + "EnableExternalVideoPlayers": "\u542f\u7528\u5916\u90e8\u64ad\u653e\u5668", + "EnableExternalVideoPlayersHelp": "\u5f53\u4f60\u5f00\u59cb\u64ad\u653e\u89c6\u9891\u65f6\uff0c\u5c06\u4f1a\u663e\u793a\u4e00\u4e2a\u5916\u90e8\u64ad\u653e\u5668\u83dc\u5355\u3002", + "HeaderSpecialEpisodeInfo": "\u7279\u522b\u5267\u96c6\u4fe1\u606f", + "LabelAirsBeforeSeason": "\u5b63\u64ad\u51fa\u524d\uff1a", + "LabelAirsAfterSeason": "\u5b63\u64ad\u51fa\u540e\uff1a", + "LabelAirsBeforeEpisode": "\u96c6\u64ad\u51fa\u524d\uff1a", + "HeaderExternalIds": "\u5916\u90e8 Ids\uff1a", + "HeaderDisplaySettings": "\u663e\u793a\u8bbe\u7f6e", + "LabelDisplayOrder": "\u663e\u793a\u987a\u5e8f\uff1a", + "Display": "\u663e\u793a", + "Countries": "\u56fd\u5bb6", + "Genres": "\u98ce\u683c", + "Studios": "\u5de5\u4f5c\u5ba4", + "Tags": "\u6807\u7b7e", + "HeaderMetadataSettings": "\u5143\u6570\u636e\u8bbe\u7f6e", + "People": "\u4eba\u7269", + "LabelMetadataDownloadLanguage": "\u9996\u9009\u4e0b\u8f7d\u8bed\u8a00\uff1a", + "LabelLockItemToPreventChanges": "\u9501\u5b9a\u6b64\u9879\u76ee\u9632\u6b62\u6539\u52a8", + "MessageLeaveEmptyToInherit": "\u7559\u7a7a\u5219\u7ee7\u627f\u7236\u9879\u6216\u5168\u5c40\u9ed8\u8ba4\u503c\u8bbe\u7f6e\u3002", + "LabelCountry": "\u56fd\u5bb6\uff1a", + "LabelDynamicExternalId": "{0} Id\uff1a", + "LabelBirthYear": "\u51fa\u751f\u5e74\u4efd\uff1a", + "LabelBirthDate": "\u51fa\u751f\u65e5\u671f\uff1a", + "LabelDeathDate": "\u53bb\u4e16\u65e5\u671f\uff1a", + "LabelEndDate": "\u7ed3\u675f\u65e5\u671f\uff1a", + "LabelSeasonNumber": "\u5b63\u53f7\uff1a", + "LabelEpisodeNumber": "\u96c6\u53f7\uff1a", + "LabelTrackNumber": "\u97f3\u8f68\u53f7\u7801\uff1a", + "LabelNumber": "\u7f16\u53f7\uff1a", + "LabelDiscNumber": "\u5149\u76d8\u53f7\uff1a", + "LabelParentNumber": "\u7236\u7f16\u53f7\uff1a", + "SortName": "\u6392\u5e8f\u540d\u79f0", + "ReleaseDate": "\u53d1\u884c\u65e5\u671f", + "Continuing": "\u7ee7\u7eed", + "Ended": "\u7ed3\u675f", + "HeaderEnabledFields": "\u5df2\u542f\u7528\u7684\u680f", + "HeaderEnabledFieldsHelp": "\u53cd\u9009\u680f\u4ee5\u9501\u5b9a\u5e76\u4e0d\u8ba9\u5176\u6570\u636e\u88ab\u66f4\u6539\u3002", + "Backdrops": "\u80cc\u666f", + "Images": "\u56fe\u7247", + "Runtime": "\u64ad\u653e\u65f6\u957f", + "ProductionLocations": "\u4ea7\u5730", + "BirthLocation": "\u51fa\u751f\u5730", + "ParentalRating": "\u5bb6\u957f\u5206\u7ea7", + "PlayCount": "\u64ad\u653e\u6b21\u6570", + "Name": "\u540d\u79f0", + "Overview": "\u6982\u8ff0", + "LabelType": "\u7c7b\u578b\uff1a", + "LabelPersonRole": "\u89d2\u8272\uff1a", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "\u6f14\u5458", + "Composer": "\u4f5c\u66f2\u5bb6", + "Director": "\u5bfc\u6f14", + "GuestStar": "\u7279\u9080\u660e\u661f", + "Producer": "\u5236\u7247\u4eba", + "Writer": "\u7f16\u5267", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "\u6b63\u5728\u5b89\u88c5 {0}", + "PackageInstallCompleted": "{0} \u5b89\u88c5\u5b8c\u6210\u3002", + "PackageInstallFailed": "{0} \u5b89\u88c5\u5931\u8d25\u3002", + "PackageInstallCancelled": "{0} \u5b89\u88c5\u88ab\u53d6\u6d88\u3002", + "SeriesYearToPresent": "{0} - \u73b0\u5728", + "ValueOneItem": "1 item", + "ValueOneSong": "1\u9996\u6b4c", + "ValueSongCount": "{0} \u9996\u6b4c", + "ValueOneMovie": "1 \u4e2a\u7535\u5f71", + "ValueMovieCount": "{0} \u4e2a\u7535\u5f71", + "ValueOneSeries": "1 \u4e2a\u7cfb\u5217", + "ValueSeriesCount": "{0} \u4e2a\u7cfb\u5217", + "ValueOneEpisode": "1 \u96c6", + "ValueEpisodeCount": "{0} \u96c6", + "ValueOneGame": "1 \u4e2a\u6e38\u620f", + "ValueGameCount": "{0} \u4e2a\u6e38\u620f", + "ValueOneAlbum": "1\u5f20\u4e13\u8f91", + "ValueAlbumCount": "{0} \u5f20\u4e13\u8f91", + "ValueOneMusicVideo": "1\u4e2a\u97f3\u4e50\u89c6\u9891", + "ValueMusicVideoCount": "{0} \u4e2a\u97f3\u4e50\u89c6\u9891", + "ValueMinutes": "{0} \u5206\u949f", + "Albums": "\u4e13\u8f91", + "Songs": "\u6b4c\u66f2", + "Books": "\u4e66\u7c4d", + "HeaderAudioBooks": "\u6709\u58f0\u8bfb\u7269", + "HeaderIdentifyItemHelp": "\u8f93\u5165\u4e00\u4e2a\u6216\u591a\u4e2a\u641c\u7d22\u6761\u4ef6\u3002\u5220\u9664\u6761\u4ef6\u53ef\u5f97\u5230\u66f4\u591a\u641c\u7d22\u7ed3\u679c\u3002", + "PleaseEnterNameOrId": "\u8bf7\u8f93\u5165\u4e00\u4e2a\u540d\u79f0\u6216\u4e00\u4e2a\u5916\u90e8ID\u3002", + "MessageItemSaved": "\u9879\u76ee\u5df2\u4fdd\u5b58\u3002", + "SearchResults": "\u641c\u7d22\u7ed3\u679c", + "ServerNameIsRestarting": "Emby Server - {0} \u91cd\u542f\u4e2d\u3002", + "ServerNameIsShuttingDown": "Emby \u670d\u52a1\u5668 - {0} \u6b63\u5728\u5173\u95ed\u3002", + "HeaderDeleteItems": "\u5220\u9664\u9879\u76ee", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "\u8bf7\u91cd\u542f Emby \u670d\u52a1\u5668 - {0}\u3002", + "LabelSyncJobName": "\u540c\u6b65\u4efb\u52a1\u540d\u79f0\uff1a", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "\u8d28\u91cf\uff1a", + "LabelSyncNoTargetsHelp": "\u770b\u8d77\u6765\u60a8\u76ee\u524d\u8fd8\u6ca1\u6709\u4efb\u4f55\u5e94\u7528\u7a0b\u5e8f\u652f\u6301\u79bb\u7ebf\u4e0b\u8f7d\u3002", + "DownloadingDots": "\u6b63\u5728\u4e0b\u8f7d...", + "HeaderSyncRequiresSub": "\u4e0b\u8f7d\u9700\u8981\u4e00\u4e2a\u6709\u6548\u7684 Emby Premiere \u8ba2\u9605\u3002", + "LearnMore": "\u4e86\u89e3\u66f4\u591a", + "LabelProfile": "\u914d\u7f6e\uff1a", + "LabelBitrateMbps": "\u6bd4\u7279\u7387 (Mbps)\uff1a", + "ConvertUnwatchedVideosOnly": "\u4ec5\u8f6c\u6362\u672a\u89c2\u770b\u7684\u89c6\u9891", + "SyncUnwatchedVideosOnly": "\u4ec5\u4e0b\u8f7d\u672a\u89c2\u770b\u7684\u89c6\u9891", + "ConvertUnwatchedVideosOnlyHelp": "\u53ea\u6709\u672a\u89c2\u770b\u7684\u89c6\u9891\u4f1a\u88ab\u8f6c\u6362\u3002", + "SyncUnwatchedVideosOnlyHelp": "\u53ea\u6709\u672a\u89c2\u770b\u7684\u89c6\u9891\u4f1a\u88ab\u4e0b\u8f7d\uff0c\u5e76\u4e14\u5df2\u7ecf\u89c2\u770b\u8fc7\u7684\u89c6\u9891\u4f1a\u4ece\u8be5\u8bbe\u5907\u4e0a\u79fb\u9664\u3002", + "AutomaticallySyncNewContent": "\u81ea\u52a8\u4e0b\u8f7d\u65b0\u5185\u5bb9", + "AutomaticallySyncNewContentHelp": "\u6dfb\u52a0\u5230\u8fd9\u4e2a\u6587\u4ef6\u5939\u7684\u65b0\u5185\u5bb9\u5c06\u4f1a\u88ab\u81ea\u52a8\u4e0b\u8f7d\u5230\u8bbe\u5907\u4e0a\u3002", + "AutomaticallyConvertNewContent": "\u81ea\u52a8\u8f6c\u6362\u65b0\u5185\u5bb9", + "AutomaticallyConvertNewContentHelp": "\u6dfb\u52a0\u5230\u8fd9\u4e2a\u6587\u4ef6\u5939\u7684\u65b0\u5185\u5bb9\u5c06\u4f1a\u88ab\u81ea\u52a8\u8f6c\u6362\u3002", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "\u8bf7\u9009\u62e9\u8981\u4e0b\u8f7d\u7684\u8bbe\u5907\u3002", + "Screenshots": "\u622a\u56fe", + "MoveRight": "\u53f3\u79fb", + "MoveLeft": "\u5de6\u79fb", + "ConfirmDeleteImage": "\u5220\u9664\u56fe\u7247\uff1f", + "HeaderEditImages": "\u4fee\u6539\u56fe\u7247", + "Settings": "\u8bbe\u7f6e", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "\u65b0\u5267\u96c6", + "Episodes": "\u5267\u96c6", + "HDPrograms": "\u9ad8\u6e05\u8282\u76ee", + "Programs": "Programs", + "LiveBroadcasts": "Live broadcasts", + "Premieres": "Premieres", + "RepeatEpisodes": "Repeat episodes", + "DvrSubscriptionRequired": "Emby DVR requires an active Emby Premiere subscription.", + "HeaderCancelRecording": "Cancel Recording", + "CancelRecording": "\u53d6\u6d88\u5f55\u5236", + "HeaderKeepRecording": "Keep Recording", + "HeaderCancelSeries": "Cancel Series", + "HeaderKeepSeries": "Keep Series", + "HeaderLearnMore": "\u4e86\u89e3\u66f4\u591a", + "DeleteMedia": "\u5220\u9664\u5a92\u4f53", + "SeriesSettings": "\u7cfb\u5217\u8bbe\u5b9a", + "HeaderRecordingOptions": "\u5f55\u5236\u9009\u9879", + "CancelSeries": "\u53d6\u6d88\u7cfb\u5217", + "DoNotRecord": "\u4e0d\u5f55\u5236", + "HeaderSeriesOptions": "\u7cfb\u5217\u9009\u9879", + "LabelChannels": "\u9891\u9053\uff1a", + "ChannelNameOnly": "\u53ea\u5728\u9891\u9053 {0}", + "Anytime": "\u4efb\u4f55\u65f6\u95f4", + "AnyLanguage": "Any language", + "AroundTime": "{0} \u5de6\u53f3", + "All": "All", + "AllChannels": "\u6240\u6709\u9891\u9053", + "LabelRecord": "\u5f55\u5236\uff1a", + "NewEpisodesOnly": "\u53ea\u65b0\u96c6", + "AllEpisodes": "\u6240\u6709\u96c6", + "LabelStartWhenPossible": "\u5f53\u53ef\u80fd\u65f6\u81ea\u52a8\u5f00\u59cb\uff1a", + "LabelStopWhenPossible": "\u5f53\u53ef\u80fd\u65f6\u81ea\u52a8\u505c\u6b62\uff1a", + "MinutesBefore": "\u5206\u949f\u524d", + "MinutesAfter": "\u5206\u949f\u540e", + "SkipEpisodesAlreadyInMyLibrary": "\u4e0d\u5f55\u5236\u6211\u7684\u5a92\u4f53\u5e93\u91cc\u5df2\u5b58\u5728\u7684\u5267\u96c6", + "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", + "LabelKeepUpTo": "Keep up to:", + "AsManyAsPossible": "\u5c3d\u53ef\u80fd\u591a", + "DefaultErrorMessage": "\u5904\u7406\u8bf7\u6c42\u65f6\u53d1\u751f\u9519\u8bef\u3002\u8bf7\u7a0d\u540e\u5c1d\u8bd5\u3002", + "LabelKeep:": "\u4fdd\u7559\uff1a", + "UntilIDelete": "\u76f4\u5230\u6211\u5220\u9664", + "UntilSpaceNeeded": "\u76f4\u5230\u9700\u8981\u7a7a\u95f4", + "Categories": "\u5206\u7c7b", + "Sports": "\u4f53\u80b2", + "News": "\u65b0\u95fb", + "Movies": "\u7535\u5f71", + "Kids": "\u513f\u7ae5", + "EnableColorCodedBackgrounds": "Enable color coded backgrounds", + "SortChannelsBy": "\u9891\u9053\u6392\u5e8f\u65b9\u5f0f\uff1a", + "RecentlyWatched": "\u6700\u8fd1\u89c2\u770b", + "ChannelNumber": "Channel number", + "HeaderBenefitsEmbyPremiere": "Benefits of Emby Premiere", + "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Emby.", + "HeaderTryPlayback": "Try Playback", + "HowDidYouPay": "\u4f60\u60f3\u5982\u4f55\u4ed8\u6b3e\uff1f", + "IHaveEmbyPremiere": "I have Emby Premiere", + "IPurchasedThisApp": "\u6211\u5df2\u8d2d\u4e70\u6b64\u5e94\u7528", + "ButtonRestorePreviousPurchase": "\u6062\u590d\u8d2d\u4e70", + "ButtonUnlockWithPurchase": "\u8d2d\u4e70\u4ee5\u89e3\u9501", + "ButtonUnlockPrice": "\u89e3\u9501 {0}", + "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}", + "HeaderAlreadyPaid": "\u5df2\u4ed8\u6b3e\uff1f", + "ButtonPlayOneMinute": "\u64ad\u653e\u4e00\u5206\u949f", + "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", + "HeaderUnlockFeature": "\u89e3\u9501\u529f\u80fd", + "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": "\u64ad\u653e\u6211\u7684\u5a92\u4f53", + "HeaderDiscoverEmbyPremiere": "\u53d1\u73b0 Emby Premiere", + "Items": "Items", + "OneChannel": "\u4e00\u4e2a\u9891\u9053", + "ConfirmRemoveDownload": "\u5220\u9664\u4e0b\u8f7d\uff1f", + "RemoveDownload": "\u79fb\u9664\u4e0b\u8f7d", + "KeepDownload": "Keep download", + "AddedOnValue": "\u5df2\u6dfb\u52a0 {0}", + "RemovingFromDevice": "\u4ece\u8bbe\u5907\u79fb\u9664\u4e2d", + "KeepOnDevice": "Keep on device", + "CancelDownload": "\u53d6\u6d88\u4e0b\u8f7d", + "SyncJobItemStatusReadyToTransfer": "\u4f20\u8f93\u5c31\u7eea", + "SyncJobItemStatusSyncedMarkForRemoval": "\u4ece\u8bbe\u5907\u79fb\u9664\u4e2d", + "SyncJobItemStatusQueued": "\u5df2\u5217\u961f", + "SyncJobItemStatusConverting": "\u8f6c\u6362\u4e2d", + "SyncJobItemStatusTransferring": "\u4f20\u8f93\u4e2d", + "SyncJobItemStatusSynced": "\u5df2\u4e0b\u8f7d", + "SyncJobItemStatusFailed": "\u5df2\u5931\u8d25", + "SyncJobItemStatusRemovedFromDevice": "\u5df2\u4ece\u8bbe\u5907\u79fb\u9664", + "SyncJobItemStatusCancelled": "\u5df2\u53d6\u6d88", + "Retry": "\u91cd\u8bd5", + "HeaderMyDevice": "\u6211\u7684\u8bbe\u5907", + "Continue": "\u7ee7\u7eed", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "\u8fdc\u7a0b\u63a7\u5236", + "Disconnect": "\u65ad\u5f00\u8fde\u63a5", + "EnableDisplayMirroring": "\u5f00\u542f\u663e\u793a\u955c\u50cf", + "HeaderPlayOn": "Play On", + "Quality": "\u8d28\u91cf", + "Auto": "\u81ea\u52a8", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "\u539f\u59cb\u7684", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "\u63a5\u53d7", + "Reject": "\u62d2\u7edd", + "Connect": "\u8fde\u63a5", + "HeaderMyMedia": "\u6211\u7684\u5a92\u4f53", + "HeaderMyMediaSmall": "\u6211\u7684\u5a92\u4f53 (\u5c0f)", + "LatestFromLibrary": "\u6700\u65b0\u7684{0}", + "ContinueWatching": "\u7ee7\u7eed\u89c2\u770b", + "HeaderLatestChannelMedia": "\u6700\u65b0\u9891\u9053\u9879\u76ee", + "HeaderContinueWatching": "\u7ee7\u7eed\u89c2\u770b", + "HeaderContinueListening": "\u7ee7\u7eed\u542c", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "\u540c\u6b65\u5230\uff1a", + "LabelConvertTo": "\u8f6c\u6362\u4e3a\uff1a", + "Next": "\u4e0b\u4e00\u4e2a", + "LabelSource": "\u6765\u6e90\uff1a", + "LabelVersion": "\u7248\u672c\uff1a", + "AllLanguages": "\u6240\u6709\u8bed\u8a00", + "Previous": "\u4e0a\u4e00\u4e2a", + "HeaderNextUp": "\u4e0b\u4e00\u4e2a", + "HeaderLatestFrom": "\u6700\u65b0\u7684 {0}", + "LabelHomeScreenSectionValue": "\u4e3b\u5c4f\u5e55\u6a21\u5757{0}:", + "SettingsSaved": "\u8bbe\u7f6e\u5df2\u4fdd\u5b58\u3002", + "None": "\u65e0", + "More": "\u66f4\u591a", + "Up": "\u4e0a", + "Down": "\u4e0b", + "Home": "\u9996\u9875", + "Favorites": "\u6211\u7684\u6700\u7231", + "HeaderHomeScreen": "\u4e3b\u5c4f\u5e55", + "HeaderLatestChannelItems": "\u6700\u65b0\u9891\u9053\u9879\u76ee", + "HeaderLibraryOrder": "\u5a92\u4f53\u5e93\u987a\u5e8f", + "HideWatchedContentFromLatestMedia": "\u4ece\u6700\u65b0\u5a92\u4f53\u4e2d\u9690\u85cf\u5df2\u89c2\u770b\u7684\u5185\u5bb9", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "\u64ad\u653e\u9519\u8bef", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "\u8bf7\u63d2\u5165\u5149\u76d8\u4ee5\u64ad\u653e\u6b64\u89c6\u9891\u3002", + "Guide": "Guide", + "Suggestions": "\u5efa\u8bae", + "HeaderFavoriteCollections": "\u6700\u7231\u7684\u6536\u85cf", + "HeaderFavoritePlaylists": "\u6700\u7231\u7684\u64ad\u653e\u5217\u8868", + "Collections": "\u6536\u85cf", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "\u6587\u4ef6\u5939", + "DisplayInOtherHomeScreenSections": "\u5728\u201c\u6700\u65b0\u7684\u5a92\u4f53\u201d\u548c\u201c\u7ee7\u7eed\u89c2\u770b\u201c\u7b49\u4e3b\u5c4f\u5e55\u6a21\u5757\u4e2d\u663e\u793a", + "DisplayInMyMedia": "\u5728\u4e3b\u5c4f\u5e55\u663e\u793a", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "\u5faa\u73af\u6a21\u5f0f", + "RepeatOne": "\u5355\u9879\u5faa\u73af", + "RepeatAll": "\u5168\u90e8\u5faa\u73af", + "LabelDefaultScreen": "\u9ed8\u8ba4\u5206\u9875\uff1a", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "\u662f", + "No": "\u5426", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "\u6807\u8bb0\u4e3a\u5df2\u89c2\u770b", + "ScanForNewAndUpdatedFiles": "\u626b\u63cf\u65b0\u7684\u548c\u6709\u4fee\u6539\u7684\u6587\u4ef6", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "\u76f4\u63a5\u4e32\u6d41\u4e00\u4e2a\u6587\u4ef6\u4ec5\u4ec5\u4f1a\u5360\u7528\u975e\u5e38\u5c11\u7684\u5904\u7406\u80fd\u529b\u5e76\u4e14\u89c6\u9891\u7684\u54c1\u8d28\u4e0d\u4f1a\u6709\u4efb\u4f55\u635f\u5931\u3002", + "MediaIsBeingConverted": "\u5a92\u4f53\u6b63\u5728\u88ab\u8f6c\u6362\u6210\u4e0e\u6b63\u5728\u64ad\u653e\u8be5\u5a92\u4f53\u7684\u8bbe\u5907\u517c\u5bb9\u7684\u683c\u5f0f\u3002", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "\u8f6c\u7801\u7684\u539f\u56e0\uff1a", + "DirectPlaying": "\u76f4\u63a5\u64ad\u653e", + "DirectStreaming": "\u76f4\u63a5\u4e32\u6d41", + "Transcoding": "\u8f6c\u7801", + "ContainerBitrateExceedsLimit": "\u5a92\u4f53\u6bd4\u7279\u7387\u8d85\u8fc7\u9650\u5236\u3002", + "VideoCodecNotSupported": "\u89c6\u9891\u7f16\u7801\u4e0d\u53d7\u652f\u6301", + "AudioCodecNotSupported": "\u97f3\u9891\u7f16\u7801\u4e0d\u53d7\u652f\u6301", + "SubtitleCodecNotSupported": "\u5b57\u5e55\u683c\u5f0f\u4e0d\u88ab\u652f\u6301", + "DirectPlayError": "\u76f4\u63a5\u64ad\u653e\u53d1\u751f\u9519\u8bef", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "\u97f3\u9891\u6bd4\u7279\u7387\u4e0d\u53d7\u652f\u6301", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby \u8d26\u6237\u5df2\u6dfb\u52a0", + "LabelSubtitlePlaybackMode": "\u5b57\u5e55\u6a21\u5f0f\uff1a", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "\u65e0\u5b57\u5e55", + "Default": "\u9ed8\u8ba4", + "Absolute": "Absolute", + "Smart": "\u667a\u80fd\u6a21\u5f0f", + "Small": "\u5c0f", + "Smaller": "Smaller", + "Medium": "\u6807\u51c6", + "Large": "\u5927", + "ExtraLarge": "\u7279\u5927", + "OnlyForcedSubtitles": "\u53ea\u663e\u793a\u5f3a\u5236\u5b57\u5e55", + "AlwaysPlaySubtitles": "\u603b\u662f\u663e\u793a\u5b57\u5e55", + "DefaultSubtitlesHelp": "\u5b57\u5e55\u5c06\u57fa\u4e8e\u5185\u5d4c\u5143\u6570\u636e\u4e2d\u7684\u201c\u9ed8\u8ba4\u201d\u6807\u5fd7\u548c\u201c\u5f3a\u5236\u201d\u6807\u5fd7\u6765\u8f7d\u5165\u3002\u5f53\u591a\u4e2a\u9009\u9879\u53ef\u7528\u65f6\uff0c\u5c06\u6839\u636e\u8bed\u8a00\u504f\u597d\u51b3\u5b9a\u3002", + "SmartSubtitlesHelp": "\u5f53\u97f3\u9891\u4e3a\u5916\u8bed\u65f6\uff0c\u5c06\u52a0\u8f7d\u4e0e\u8bed\u8a00\u504f\u597d\u5339\u914d\u7684\u5b57\u5e55\u3002", + "HeaderSubtitleSettings": "\u5b57\u5e55\u8bbe\u7f6e", + "HeaderSubtitleAppearance": "\u5b57\u5e55\u5916\u89c2", + "OnlyForcedSubtitlesHelp": "\u53ea\u6709\u88ab\u6807\u8bb0\u4e3a\u201c\u5f3a\u5236\u201d\u7684\u5b57\u5e55\u4f1a\u88ab\u52a0\u8f7d\u3002", + "AlwaysPlaySubtitlesHelp": "\u65e0\u8bba\u97f3\u9891\u4e3a\u4f55\u79cd\u8bed\u8a00\uff0c\u90fd\u5c06\u52a0\u8f7d\u4e0e\u8bed\u8a00\u504f\u597d\u5339\u914d\u7684\u5b57\u5e55\u3002", + "NoSubtitlesHelp": "\u5b57\u5e55\u5c06\u9ed8\u8ba4\u4e0d\u88ab\u52a0\u8f7d\uff0c\u4f46\u4f60\u4ecd\u7136\u53ef\u4ee5\u5728\u64ad\u653e\u65f6\u624b\u52a8\u6253\u5f00\u5b57\u5e55\u3002", + "LabelPreferredSubtitleLanguage": "\u5b57\u5e55\u8bed\u8a00\u504f\u597d\uff1a", + "LabelTextSize": "\u6587\u672c\u5927\u5c0f\uff1a", + "TheseSettingsAffectSubtitlesOnThisDevice": "\u8fd9\u4e9b\u8bbe\u7f6e\u4ec5\u5f71\u54cd\u8be5\u8bbe\u5907\u7684\u5b57\u5e55\u663e\u793a", + "LabelDropShadow": "\u9634\u5f71\uff1a", + "LabelTextBackgroundColor": "\u6587\u672c\u80cc\u666f\u8272\uff1a", + "LabelWindowBackgroundColor": "\u6587\u672c\u80cc\u666f\u8272\uff1a", + "LabelFont": "\u5b57\u4f53\uff1a", + "LabelTextColor": "\u6587\u672c\u989c\u8272\uff1a", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "\u9634\u5f71", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "\u8fd9\u4e9b\u8bbe\u7f6e\u5c06\u4e0d\u4f1a\u5e94\u7528\u4e8e\u56fe\u5f62\u5b57\u5e55\uff08\u5982 PGS,DVD \u7b49\uff09\uff0c\u6216\u8005\u4e00\u4e9b\u6709\u7740\u81ea\u5df1\u7684\u5185\u7f6e\u5f0f\u6837\u7684\u5b57\u5e55\uff08ASS\/SSA)\u3002", + "LabelBurnSubtitles": "\u70e7\u5f55\u5b57\u5e55\uff1a", + "OnlyImageFormats": "\u4ec5\u56fe\u50cf\u683c\u5f0f\uff08VOBSUB, PGS, SUB\/IDX \u7b49\uff09", + "Normal": "\u666e\u901a", + "BurnSubtitlesHelp": "\u6839\u636e\u5b57\u5e55\u683c\u5f0f\u786e\u5b9a\u670d\u52a1\u5668\u5728\u8f6c\u6362\u89c6\u9891\u65f6\u662f\u5426\u5e94\u70e7\u5f55\u5b57\u5e55\u3002\u907f\u514d\u70e7\u5f55\u5b57\u5e55\u4f1a\u63d0\u9ad8\u670d\u52a1\u5668\u6027\u80fd\u3002\u9009\u62e9\u201c\u81ea\u52a8\u201d\u4ee5\u70e7\u5f55\u57fa\u4e8e\u56fe\u50cf\u7684\u5b57\u5e55\u683c\u5f0f\uff08\u5982 VOBSUB, PGS, SUB\/IDX \u7b49\uff09\u548c\u4e00\u4e9b\u590d\u6742\u7684 ASS\/SSA \u5b57\u5e55\u3002", + "AllComplexFormats": "\u6240\u6709\u590d\u6742\u7684\u683c\u5f0f\uff08ASS, SSA, VOBSUB, PGS, SUB\/IDX \u7b49\uff09", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "\u8fd9\u4e9b\u8bbe\u5b9a\u4e5f\u4f1a\u88ab\u5e94\u7528\u4e8e\u4efb\u4f55\u901a\u8fc7\u6b64\u8bbe\u5907\u53d1\u8d77\u7684 Chromecast \u64ad\u653e\u3002", + "HeaderWaitingForWifi": "\u7b49\u5f85 Wifi \u8fde\u63a5", + "WifiRequiredToDownload": "\u9700\u8981\u8fde\u63a5 Wifi \u624d\u80fd\u7ee7\u7eed\u4e0b\u8f7d\u3002", + "HeaderDownloadSettings": "\u4e0b\u8f7d\u8bbe\u7f6e", + "Hide": "\u9690\u85cf", + "HeaderStartNow": "\u73b0\u5728\u5f00\u59cb", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} \u79d2", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "\u6d4f\u89c8", + "HeaderUploadImage": "\u4e0a\u4f20\u56fe\u7247", + "HeaderAddUpdateImage": "\u6dfb\u52a0\/\u66f4\u65b0 \u56fe\u7247", + "LabelImageType": "\u56fe\u7247\u7c7b\u578b\uff1a", + "Upload": "\u4e0a\u4f20", + "Primary": "\u5c01\u9762\u56fe", + "Art": "Art", + "Backdrop": "\u80cc\u666f", + "Banner": "\u6a2a\u5e45", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "\u5149\u76d8", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "\u7f29\u7565\u56fe", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "\u9996\u9009\u97f3\u9891\u8bed\u8a00\uff1a", + "LabelPlayDefaultAudioTrack": "\u64ad\u653e\u9ed8\u8ba4\u97f3\u8f68\u65e0\u8bba\u662f\u4ec0\u4e48\u8bed\u8a00", + "HeaderVideoQuality": "\u89c6\u9891\u8d28\u91cf", + "CinemaModeConfigurationHelp": "\u5f71\u9662\u6a21\u5f0f\u76f4\u63a5\u4e3a\u60a8\u7684\u5ba2\u5385\u5e26\u6765\u5267\u573a\u7ea7\u4f53\u9a8c\uff0c\u540c\u65f6\u8fd8\u53ef\u4ee5\u64ad\u653e\u9884\u544a\u7247\u548c\u81ea\u5b9a\u4e49\u4ecb\u7ecd\u3002", + "EnableNextVideoInfoOverlay": "\u5728\u64ad\u653e\u65f6\u542f\u7528\u4e0b\u4e00\u4e2a\u89c6\u9891\u4fe1\u606f", + "EnableNextVideoInfoOverlayHelp": "\u5728\u89c6\u9891\u7ed3\u5c3e\u5904\uff0c\u663e\u793a\u5f53\u524d\u64ad\u653e\u5217\u8868\u4e2d\u4e0b\u4e00\u4e2a\u89c6\u9891\u7684\u4fe1\u606f\u3002", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "\u6700\u5927 Chromecast \u6bd4\u7279\u7387\uff1a", + "LabelSkipBackLength": "\u8df3\u8fc7\u957f\u5ea6\uff1a", + "LabelSkipForwardLength": "\u5feb\u8fdb\u957f\u5ea6", + "EnableCinemaMode": "\u542f\u7528\u5f71\u9662\u6a21\u5f0f", + "LabelInternetQuality": "\u7f51\u7edc\u8d28\u91cf\uff1a", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "\u5bb6\u5ead\u7f51\u7edc\u8d28\u91cf\uff1a", + "HeaderLatestMedia": "\u6700\u65b0\u5a92\u4f53", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "\u5141\u8bb8\u81ea\u52a8\u5207\u6362\u5b63\u8282\u6027\u4e3b\u9898", + "AllowSeasonalThemesHelp": "\u5982\u679c\u542f\u7528\uff0c\u5f53\u5b63\u8282\u6027\u4e3b\u9898\u4f7f\u7528\u65f6\u4f1a\u8986\u76d6\u4f60\u7684\u4e3b\u9898\u8bbe\u7f6e\u3002", + "AutoBasedOnLanguageSetting": "\u81ea\u52a8\uff08\u53d6\u51b3\u4e8e\u8bed\u8a00\u8bbe\u7f6e\uff09", + "LabelDateTimeLocale": "\u65f6\u533a\u8bbe\u7f6e\uff1a", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "\u5b57\u5e55\uff1a", + "Off": "Off", + "ShowTitle": "\u663e\u793a\u6807\u9898", + "ShowYear": "Show year", + "Filters": "\u7b5b\u9009", + "Unplayed": "\u672a\u64ad\u653e", + "LabelTVHomeScreen": "TV \u6a21\u5f0f\u4e3b\u5c4f\u5e55\uff1a", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "\u9884\u544a\u7247", + "Extras": "\u989d\u5916", + "ThemeSongs": "\u4e3b\u9898\u66f2", + "ThemeVideos": "\u4e3b\u9898\u89c6\u9891", + "HeaderFavoriteMovies": "\u6700\u7231\u7684\u7535\u5f71", + "HeaderFavoriteShows": "\u6700\u7231\u7684\u8282\u76ee", + "HeaderFavoriteEpisodes": "\u6700\u7231\u7684\u5267\u96c6", + "HeaderFavoriteVideos": "\u6700\u7231\u7684\u89c6\u9891", + "HeaderFavoriteGames": "\u6700\u7231\u7684\u6e38\u620f", + "HeaderFavoriteArtists": "\u6700\u7231\u7684\u827a\u672f\u5bb6", + "HeaderFavoriteAlbums": "\u6700\u7231\u7684\u4e13\u8f91", + "HeaderFavoriteSongs": "\u6700\u7231\u7684\u6b4c\u66f2", + "Ascending": "\u5347\u5e8f", + "Descending": "\u964d\u5e8f", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/zh-hk.json b/src/bower_components/emby-webcomponents/strings/zh-hk.json index c5b3c0dddb..e21d2509bd 100644 --- a/src/bower_components/emby-webcomponents/strings/zh-hk.json +++ b/src/bower_components/emby-webcomponents/strings/zh-hk.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "新增", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "Advanced", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "取消", - "ButtonGotIt": "Got It", - "ButtonOk": "Ok", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "重新啟動", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "Try Again", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "Confirm Deletion", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "繼續", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "錄影日", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "删除", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "Dislike", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "Download", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "編輯", - "EditImages": "Edit images", - "EditMetadata": "Edit metadata", - "EditSubtitles": "編輯字幕", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "完成", - "EndsAtValue": "Ends at {0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "Favorite", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "This feature requires an active Jellyfin Premiere subscription.", - "Features": "Features", - "File": "File", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "星期五", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "添加到收藏庫", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "Get Jellyfin Premiere", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "Delete Item", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "New Recording", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "Say Something Like...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "選擇日期", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "You Said...", - "Help": "幫助", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0} items", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "已播放劇集季度:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "尚未播放劇集季度:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "藝人:", - "LabelArtistsHelp": "分開多重使用", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "Collection:", - "LabelCommunityRating": "討論區評分", - "LabelContentType": "內容類型:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "國家:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "語言:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "偏好下載語言:", - "LabelName": "名稱:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "路徑:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "Playlist:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "Refresh mode:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "狀態:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "Like", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Jellyfin Premiere subscription is required in order to create automated series recordings.", - "MessageAreYouSureDeleteSubtitles": "您確定希望刪除此字幕文件?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "Download queued.", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "Items added.", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "星期一", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "My Subtitles", - "Name": "Name", - "NewCollection": "新收藏庫", - "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", - "NewCollectionNameExample": "例如:星球大戰收藏庫", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "No items found.", - "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "New...", - "Original": "Original", - "OriginalAirDateValue": "Original air date: {0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "播放", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "錄影", - "RecordSeries": "Record series", - "RecordingCancelled": "Recording cancelled.", - "RecordingScheduled": "Recording scheduled.", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "重新整理", - "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Jellyfin Server dashboard.", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "Replace all metadata", - "ReplaceExistingImages": "Replace existing images", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "星期六", - "Save": "儲存", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "Search", - "SearchForCollectionInternetMetadata": "從互聯網搜尋相關圖片和資料屬性", - "SearchForMissingMetadata": "Search for missing metadata", - "SearchForSubtitles": "字幕搜索", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "Series recording scheduled.", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "This Jellyfin Server needs to be updated. To download the latest version, please visit {0}", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "Share", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "Subtitles", - "Suggestions": "Suggestions", - "Sunday": "星期日", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "星期四", - "TrackCount": "{0} tracks", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "星期二", - "Uniform": "Uniform", - "UnlockGuide": "Unlock Guide", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} 劇集", - "ValueGameCount": "{0} 遊戲", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} 個 MV", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1個 MV", - "ValueOneSeries": "1 劇集", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} 劇集", - "ValueSongCount": "{0} 首歌", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "星期三", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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", + "Add": "\u65b0\u589e", + "ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0} tracks", + "ItemCount": "{0} items", + "OriginalAirDateValue": "Original air date: {0}", + "EndsAtValue": "Ends at {0}", + "HeaderSelectDate": "\u9078\u64c7\u65e5\u671f", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "Ok", + "ButtonCancel": "\u53d6\u6d88", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "Got It", + "ButtonRestart": "\u91cd\u65b0\u555f\u52d5", + "RecordingCancelled": "Recording cancelled.", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "Recording scheduled.", + "SeriesRecordingScheduled": "Series recording scheduled.", + "HeaderNewRecording": "New Recording", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "\u661f\u671f\u65e5", + "Monday": "\u661f\u671f\u4e00", + "Tuesday": "\u661f\u671f\u4e8c", + "Wednesday": "\u661f\u671f\u4e09", + "Thursday": "\u661f\u671f\u56db", + "Friday": "\u661f\u671f\u4e94", + "Saturday": "\u661f\u671f\u516d", + "Days": "\u9304\u5f71\u65e5", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "Record series", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "Get Emby Premiere", + "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", + "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.", + "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "\u9304\u5f71", + "Save": "\u5132\u5b58", + "Edit": "\u7de8\u8f2f", + "Download": "Download", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "Advanced", + "Delete": "\u5220\u9664", + "HeaderDeleteItem": "Delete Item", + "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", + "Refresh": "\u91cd\u65b0\u6574\u7406", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "\u6dfb\u52a0\u5230\u6536\u85cf\u5eab", + "NewCollection": "\u65b0\u6536\u85cf\u5eab", + "LabelCollection": "Collection:", + "Help": "\u5e6b\u52a9", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", + "SearchForCollectionInternetMetadata": "\u5f9e\u4e92\u806f\u7db2\u641c\u5c0b\u76f8\u95dc\u5716\u7247\u548c\u8cc7\u6599\u5c6c\u6027", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "\u540d\u7a31\uff1a", + "NewCollectionNameExample": "\u4f8b\u5982\uff1a\u661f\u7403\u5927\u6230\u6536\u85cf\u5eab", + "MessageItemsAdded": "Items added.", + "OptionNew": "New...", + "LabelPlaylist": "Playlist:", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "Subtitles", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "\u5b57\u5e55\u641c\u7d22", + "LabelLanguage": "\u8a9e\u8a00\uff1a", + "Search": "Search", + "NoSubtitleSearchResultsFound": "No results found.", + "File": "File", + "MessageAreYouSureDeleteSubtitles": "\u60a8\u78ba\u5b9a\u5e0c\u671b\u522a\u9664\u6b64\u5b57\u5e55\u6587\u4ef6\uff1f", + "ConfirmDeletion": "Confirm Deletion", + "MySubtitles": "My Subtitles", + "MessageDownloadQueued": "Download queued.", + "EditSubtitles": "\u7de8\u8f2f\u5b57\u5e55", + "UnlockGuide": "Unlock Guide", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "Replace existing images", + "ReplaceAllMetadata": "Replace all metadata", + "SearchForMissingMetadata": "Search for missing metadata", + "LabelRefreshMode": "Refresh mode:", + "NoItemsFound": "No items found.", + "HeaderSaySomethingLike": "Say Something Like...", + "ButtonTryAgain": "Try Again", + "HeaderYouSaid": "You Said...", + "MessageWeDidntRecognizeCommand": "We're sorry, we didn't recognize that command.", + "MessageIfYouBlockedVoice": "If you denied voice access to the app you'll need to reconfigure before trying again.", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "Favorite", + "Like": "Like", + "Dislike": "Dislike", + "RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.", + "Open": "Open", + "Play": "\u64ad\u653e", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "Edit images", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "\u5167\u5bb9\u985e\u578b\uff1a", + "LabelPath": "\u8def\u5f91:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "\u72c0\u614b\uff1a", + "LabelArtists": "\u85dd\u4eba\uff1a", + "LabelArtistsHelp": "\u5206\u958b\u591a\u91cd\u4f7f\u7528", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "\u8a0e\u8ad6\u5340\u8a55\u5206", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "\u5c1a\u672a\u64ad\u653e\u5287\u96c6\u5b63\u5ea6\uff1a", + "LabelAirsAfterSeason": "\u5df2\u64ad\u653e\u5287\u96c6\u5b63\u5ea6\uff1a", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "LabelMetadataDownloadLanguage": "\u504f\u597d\u4e0b\u8f09\u8a9e\u8a00\uff1a", + "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", + "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", + "LabelCountry": "\u570b\u5bb6\uff1a", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "\u7e7c\u7e8c", + "Ended": "\u5b8c\u6210", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} \u9996\u6b4c", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 \u5287\u96c6", + "ValueSeriesCount": "{0} \u5287\u96c6", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} \u5287\u96c6", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} \u904a\u6232", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1\u500b MV", + "ValueMusicVideoCount": "{0} \u500b MV", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/strings/zh-tw.json b/src/bower_components/emby-webcomponents/strings/zh-tw.json index f526048dfc..bca8be2e00 100644 --- a/src/bower_components/emby-webcomponents/strings/zh-tw.json +++ b/src/bower_components/emby-webcomponents/strings/zh-tw.json @@ -1,685 +1,689 @@ { - "Absolute": "Absolute", - "Accept": "Accept", - "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", - "Actor": "Actor", - "Add": "添加", - "AddToCollection": "Add to collection", - "AddToPlayQueue": "Add to play queue", - "AddToPlaylist": "Add to playlist", - "AddedOnValue": "Added {0}", - "Advanced": "進階", - "AirDate": "Air date", - "Aired": "Aired", - "Albums": "Albums", - "All": "All", - "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", - "AllEpisodes": "All episodes", - "AllLanguages": "All languages", - "AllowSeasonalThemes": "Allow automatic seasonal themes", - "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", - "AlwaysPlaySubtitles": "Always play subtitles", - "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnamorphicVideoNotSupported": "Anamorphic video not supported", - "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", - "AnyLanguage": "Any language", - "Anytime": "Anytime", - "AroundTime": "Around {0}", - "Art": "Art", - "Artists": "Artists", - "AsManyAsPossible": "As many as possible", - "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", - "AttemptingWakeServer": "Attempting to wake server. Please wait...", - "AttributeNew": "New", - "AudioBitDepthNotSupported": "Audio bit depth not supported", - "AudioBitrateNotSupported": "Audio bitrate not supported", - "AudioChannelsNotSupported": "Audio channels not supported", - "AudioCodecNotSupported": "Audio codec not supported", - "AudioProfileNotSupported": "Audio profile not supported", - "AudioSampleRateNotSupported": "Audio sample rate not supported", - "Auto": "Auto", - "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "AutomaticallyConvertNewContent": "Automatically convert new content", - "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", - "AutomaticallySyncNewContent": "Automatically download new content", - "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", - "Backdrop": "Backdrop", - "Backdrops": "Backdrops", - "Banner": "Banner", - "BestFit": "Best fit", - "BirthLocation": "Birth location", - "Books": "Books", - "Box": "Box", - "BoxRear": "Box (rear)", - "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles", - "ButtonCancel": "取消", - "ButtonGotIt": "我知道了", - "ButtonOk": "確定", - "ButtonPlayOneMinute": "Play One Minute", - "ButtonRestart": "Restart", - "ButtonRestorePreviousPurchase": "Restore Purchase", - "ButtonTryAgain": "重試", - "ButtonUnlockPrice": "Unlock {0}", - "ButtonUnlockWithPurchase": "Unlock with Purchase", - "CancelDownload": "Cancel download", - "CancelRecording": "Cancel recording", - "CancelSeries": "Cancel series", - "Categories": "Categories", - "ChannelNameOnly": "Channel {0} only", - "ChannelNumber": "Channel number", - "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", - "Collections": "Collections", - "ColorPrimaries": "Color primaries", - "ColorSpace": "Color space", - "ColorTransfer": "Color transfer", - "CommunityRating": "Community rating", - "Composer": "Composer", - "ConfigureDateAdded": "Configure how date added is determined in the Jellyfin Server dashboard under Library settings", - "ConfirmDeleteImage": "Delete image?", - "ConfirmDeleteItem": "刪除此項目時,也會一併從檔案系統及媒體櫃中刪除。確定要刪除嗎?", - "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", - "ConfirmDeletion": "確定刪除", - "ConfirmEndPlayerSession": "Would you like to shutdown Jellyfin on {0}?", - "ConfirmRemoveDownload": "Remove download?", - "Connect": "Connect", - "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", - "ContainerNotSupported": "Container not supported", - "Continue": "Continue", - "ContinueInSecondsValue": "Continue in {0} seconds.", - "ContinueWatching": "Continue watching", - "Continuing": "持續", - "Convert": "Convert", - "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", - "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", - "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", - "ConvertingDots": "Converting...", - "Countries": "Countries", - "CriticRating": "Critic rating", - "DateAdded": "Date added", - "DatePlayed": "Date played", - "Days": "錄影日", - "Default": "Default", - "DefaultErrorMessage": "There was an error processing the request. Please try again later.", - "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", - "Delete": "刪除", - "DeleteMedia": "Delete media", - "Depressed": "Depressed", - "Descending": "Descending", - "Desktop": "Desktop", - "DirectPlayError": "Direct play error", - "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", - "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", - "DirectStreaming": "Direct streaming", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directors: {0}", - "Disc": "Disc", - "Disconnect": "Disconnect", - "Dislike": "不喜歡", - "Display": "Display", - "DisplayInMyMedia": "Display on home screen", - "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", - "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", - "DoNotRecord": "Do not record", - "Down": "Down", - "Download": "下載", - "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", - "Downloaded": "Downloaded", - "Downloading": "Downloading", - "DownloadingDots": "Downloading...", - "Downloads": "Downloads", - "DownloadsValue": "{0} downloads", - "DropShadow": "Drop shadow", - "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Jellyfin DVR.", - "DvrSubscriptionRequired": "Jellyfin DVR requires an active Jellyfin Premiere subscription.", - "Edit": "編輯", - "EditImages": "編輯圖片", - "EditMetadata": "Edit metadata", - "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", - "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", - "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnableThemeSongs": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", - "Ended": "完結", - "EndsAtValue": "完結於{0}", - "Episodes": "Episodes", - "Error": "Error", - "ErrorAddingGuestAccount1": "There was an error adding the Jellyfin Connect account. Has your guest created an Jellyfin account? They can sign up at {0}.", - "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", - "ErrorAddingJellyfinConnectAccount1": "There was an error adding the Jellyfin Connect account. Have you created an Jellyfin account? Sign up at {0}.", - "ErrorAddingJellyfinConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Jellyfin account.", - "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Jellyfin Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", - "ErrorDeletingItem": "There was an error deleting the item from Jellyfin Server. Please check that Jellyfin Server has write access to the media folder and try again.", - "ErrorReachingJellyfinConnect": "There was an error reaching the Jellyfin Connect server. Please ensure you have an active internet connection and try again.", - "ErrorRemovingJellyfinConnectAccount": "There was an error removing the Jellyfin Connect account. Please ensure you have an active internet connection and try again.", - "ExtraLarge": "Extra large", - "Extras": "Extras", - "Favorite": "加到最愛", - "Favorites": "Favorites", - "FeatureRequiresJellyfinPremiere": "此功能需要有效的Jellyfin豪華版訂閱", - "Features": "Features", - "File": "檔案", - "Fill": "Fill", - "Filters": "Filters", - "Folders": "Folders", - "FormatValue": "Format: {0}", - "FreeAppsFeatureDescription": "Enjoy free access to Jellyfin apps for your devices.", - "Friday": "星期五", - "GenreValue": "Genre: {0}", - "Genres": "Genres", - "GenresValue": "Genres: {0}", - "GroupBySeries": "Group by series", - "GroupVersions": "Group versions", - "GuestStar": "Guest star", - "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", - "Guide": "Guide", - "HDPrograms": "HD programs", - "HeaderActiveRecordings": "Active Recordings", - "HeaderAddToCollection": "Add to Collection", - "HeaderAddToPlaylist": "Add to Playlist", - "HeaderAddUpdateImage": "Add/Update Image", - "HeaderAlbumArtists": "Album Artists", - "HeaderAlreadyPaid": "Already Paid?", - "HeaderAppearsOn": "Appears On", - "HeaderAudioBooks": "Audio Books", - "HeaderAudioSettings": "Audio Settings", - "HeaderBecomeProjectSupporter": "立即取得", - "HeaderBenefitsJellyfinPremiere": "Benefits of Jellyfin Premiere", - "HeaderCancelRecording": "Cancel Recording", - "HeaderCancelSeries": "Cancel Series", - "HeaderCinemaMode": "Cinema Mode", - "HeaderCloudSync": "Cloud Sync", - "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", - "HeaderContinueListening": "Continue Listening", - "HeaderContinueWatching": "Continue Watching", - "HeaderConvertYourRecordings": "Convert Your Recordings", - "HeaderCustomizeHomeScreen": "Customize Home Screen", - "HeaderDeleteItem": "刪除項目", - "HeaderDeleteItems": "Delete Items", - "HeaderDisplaySettings": "Display Settings", - "HeaderDownloadSettings": "Download Settings", - "HeaderEditImages": "Edit Images", - "HeaderEnabledFields": "Enabled Fields", - "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", - "HeaderExternalIds": "External Ids:", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteCollections": "Favorite Collections", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteGames": "Favorite Games", - "HeaderFavoriteMovies": "Favorite Movies", - "HeaderFavoritePlaylists": "Favorite Playlists", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderFavoriteVideos": "Favorite Videos", - "HeaderFreeApps": "Free Jellyfin Apps", - "HeaderHomeScreen": "Home Screen", - "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", - "HeaderInvitationSent": "Invitation Sent", - "HeaderJellyfinAccountAdded": "Jellyfin Account Added", - "HeaderJellyfinAccountRemoved": "Jellyfin Account Removed", - "HeaderKeepRecording": "Keep Recording", - "HeaderKeepSeries": "Keep Series", - "HeaderLatestChannelItems": "Latest Channel Items", - "HeaderLatestChannelMedia": "Latest Channel Items", - "HeaderLatestFrom": "Latest from {0}", - "HeaderLatestMedia": "Latest Media", - "HeaderLatestRecordings": "Latest Recordings", - "HeaderLearnMore": "Learn More", - "HeaderLibraryFolders": "Library Folders", - "HeaderLibraryOrder": "Library Order", - "HeaderMetadataSettings": "Metadata Settings", - "HeaderMusicQuality": "Music Quality", - "HeaderMyDevice": "My Device", - "HeaderMyDownloads": "My Downloads", - "HeaderMyMedia": "My Media", - "HeaderMyMediaSmall": "My Media (small)", - "HeaderNewRecording": "新錄製", - "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", - "HeaderNextUp": "Next Up", - "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", - "HeaderOfflineDownloads": "Offline Media", - "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", - "HeaderOnNow": "On Now", - "HeaderPhotoAlbums": "Photo Albums", - "HeaderPlayMyMedia": "Play my Media", - "HeaderPlayOn": "Play On", - "HeaderPlaybackError": "Playback Error", - "HeaderRecordingOptions": "Recording Options", - "HeaderRemoteControl": "Remote Control", - "HeaderRestartingJellyfinServer": "Restarting Jellyfin Server", - "HeaderSaySomethingLike": "說點東西,像是...", - "HeaderSecondsValue": "{0} Seconds", - "HeaderSelectDate": "選擇日期", - "HeaderSeriesOptions": "Series Options", - "HeaderSeriesStatus": "Series Status", - "HeaderSpecialEpisodeInfo": "Special Episode Info", - "HeaderStartNow": "Start Now", - "HeaderStopRecording": "Stop Recording", - "HeaderSubtitleAppearance": "Subtitle Appearance", - "HeaderSubtitleSettings": "Subtitle Settings", - "HeaderSyncRequiresSub": "Downloading requires an active Jellyfin Premiere subscription.", - "HeaderTermsOfPurchase": "Terms of Purchase", - "HeaderTryPlayback": "Try Playback", - "HeaderUnlockFeature": "Unlock Feature", - "HeaderUploadImage": "Upload Image", - "HeaderVideoQuality": "Video Quality", - "HeaderVideoType": "Video Type", - "HeaderWaitingForWifi": "Waiting for Wifi", - "HeaderWakeServer": "Wake Server", - "HeaderYouSaid": "您是指...", - "Help": "說明", - "Hide": "Hide", - "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", - "Home": "Home", - "Horizontal": "Horizontal", - "HowDidYouPay": "How did you pay?", - "IHaveJellyfinPremiere": "I have Jellyfin Premiere", - "IPurchasedThisApp": "I purchased this app", - "Identify": "Identify", - "Images": "Images", - "ImdbRating": "IMDb rating", - "InstallingPackage": "Installing {0}", - "InstantMix": "Instant mix", - "InterlacedVideoNotSupported": "Interlaced video not supported", - "ItemCount": "{0}個項目", - "Items": "Items", - "KeepDownload": "Keep download", - "KeepOnDevice": "Keep on device", - "Kids": "Kids", - "Label3DFormat": "3D format:", - "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:", - "LabelAirsAfterSeason": "Airs after season:", - "LabelAirsBeforeEpisode": "Airs before episode:", - "LabelAirsBeforeSeason": "Airs before season:", - "LabelAlbum": "Album:", - "LabelAlbumArtists": "Album artists:", - "LabelArtists": "Artists:", - "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", - "LabelAudioLanguagePreference": "Preferred audio language:", - "LabelBirthDate": "Birth date:", - "LabelBirthYear": "Birth year:", - "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBurnSubtitles": "Burn subtitles:", - "LabelChannels": "Channels:", - "LabelCollection": "收藏櫃:", - "LabelCommunityRating": "Community rating:", - "LabelContentType": "Content type:", - "LabelConvertTo": "Convert to:", - "LabelCountry": "國家:", - "LabelCriticRating": "Critic rating:", - "LabelCustomRating": "Custom rating:", - "LabelDashboardTheme": "Server dashboard theme:", - "LabelDateAdded": "Date added:", - "LabelDateTimeLocale": "Date time locale:", - "LabelDeathDate": "Death date:", - "LabelDefaultScreen": "Default screen:", - "LabelDiscNumber": "Disc number:", - "LabelDisplayLanguage": "Display language:", - "LabelDisplayLanguageHelp": "Translating Jellyfin is an ongoing project.", - "LabelDisplayMode": "Display mode:", - "LabelDisplayOrder": "Display order:", - "LabelDropImageHere": "Drop image here, or click to browse.", - "LabelDropShadow": "Drop shadow:", - "LabelDynamicExternalId": "{0} Id:", - "LabelEmailAddress": "E-mail address:", - "LabelEndDate": "End date:", - "LabelEpisodeNumber": "Episode number:", - "LabelFont": "Font:", - "LabelHomeNetworkQuality": "Home network quality:", - "LabelHomeScreenSectionValue": "Home screen section {0}:", - "LabelImageType": "Image type:", - "LabelInternetQuality": "Internet quality:", - "LabelItemLimit": "Item limit:", - "LabelKeep:": "Keep:", - "LabelKeepUpTo": "Keep up to:", - "LabelLanguage": "語言:", - "LabelLockItemToPreventChanges": "Lock this item to prevent future changes", - "LabelMaxChromecastBitrate": "Chromecast streaming quality:", - "LabelMetadataDownloadLanguage": "Preferred download language:", - "LabelName": "名字:", - "LabelNumber": "Number:", - "LabelOriginalAspectRatio": "Original aspect ratio:", - "LabelOriginalTitle": "Original title:", - "LabelOverview": "Overview:", - "LabelParentNumber": "Parent number:", - "LabelParentalRating": "Parental rating:", - "LabelPath": "Path:", - "LabelPersonRole": "Role:", - "LabelPersonRoleHelp": "Example: Ice cream truck driver", - "LabelPlaceOfBirth": "Place of birth:", - "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", - "LabelPlaylist": "播放清單:", - "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", - "LabelProfile": "Profile:", - "LabelQuality": "Quality:", - "LabelReasonForTranscoding": "Reason for transcoding:", - "LabelRecord": "Record:", - "LabelRefreshMode": "更新模式:", - "LabelReleaseDate": "Release date:", - "LabelRuntimeMinutes": "Run time (minutes):", - "LabelScreensaver": "Screensaver:", - "LabelSeasonNumber": "Season number:", - "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", - "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", - "LabelShortOverview": "Short overview:", - "LabelSkin": "Skin:", - "LabelSkipBackLength": "Skip back length:", - "LabelSkipForwardLength": "Skip forward length:", - "LabelSortBy": "Sort by:", - "LabelSortOrder": "Sort order:", - "LabelSortTitle": "Sort title:", - "LabelSoundEffects": "Sound effects:", - "LabelSource": "Source:", - "LabelStartWhenPossible": "Start when possible:", - "LabelStatus": "Status:", - "LabelStopWhenPossible": "Stop when possible:", - "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", - "LabelSyncJobName": "Sync job name:", - "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", - "LabelSyncTo": "Sync to:", - "LabelTVHomeScreen": "TV mode home screen:", - "LabelTagline": "Tagline:", - "LabelTextBackgroundColor": "Text background color:", - "LabelTextColor": "Text color:", - "LabelTextSize": "Text size:", - "LabelTheme": "Theme:", - "LabelTitle": "Title:", - "LabelTrackNumber": "Track number:", - "LabelType": "Type:", - "LabelVersion": "Version:", - "LabelVideo": "Video:", - "LabelWebsite": "Website:", - "LabelWindowBackgroundColor": "Text background color:", - "LabelYear": "Year:", - "Large": "Large", - "LatestFromLibrary": "Latest {0}", - "LearnHowYouCanContribute": "Learn how you can contribute.", - "LearnMore": "Learn more", - "Like": "喜歡", - "LinksValue": "Links: {0}", - "List": "List", - "Live": "Live", - "LiveBroadcasts": "Live broadcasts", - "LiveTV": "Live TV", - "LiveTvFeatureDescription": "Stream Live TV to any Jellyfin app, with a compatible TV tuner device installed on your Jellyfin Server.", - "LiveTvRequiresUnlock": "Live TV requires an active Jellyfin Premiere subscription.", - "Logo": "Logo", - "ManageRecording": "Manage recording", - "MarkPlayed": "Mark played", - "MarkUnplayed": "Mark unplayed", - "MarkWatched": "Mark watched", - "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", - "Medium": "Medium", - "Menu": "Menu", - "MessageActiveSubscriptionRequiredSeriesRecordings": "要使用自動錄製系列的功能,需要有效的Jellyfin豪華版訂閱", - "MessageAreYouSureDeleteSubtitles": "您真的要刪除這個字幕檔嗎?", - "MessageConfirmRecordingCancellation": "Cancel recording?", - "MessageDownloadQueued": "需要下載", - "MessageFileReadError": "There was an error reading the file. Please try again.", - "MessageIfYouBlockedVoice": "如果您拒絕程式使用語音辨識,您將需要在重試之前再次設定", - "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Jellyfin.", - "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", - "MessageItemSaved": "Item saved.", - "MessageItemsAdded": "已新增項目", - "MessageJellyfinAccontRemoved": "The Jellyfin account has been removed from this user.", - "MessageJellyfinAccountAdded": "The Jellyfin account has been added to this user.", - "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", - "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", - "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", - "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", - "MessagePendingJellyfinAccountAdded": "The Jellyfin account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", - "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Jellyfin Server administrator for more information.", - "MessageToValidateSupporter": "If you have an active Jellyfin Premiere subscription, ensure you've setup Jellyfin Premiere in your Jellyfin Server Dashboard, which you can access by clicking Jellyfin Premiere within the main menu.", - "MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Jellyfin Premiere subscription.", - "MessageUnlockAppWithSupporter": "Unlock this feature with an active Jellyfin Premiere subscription.", - "MessageWeDidntRecognizeCommand": "很抱歉,我們無法辨識此指令", - "MinutesAfter": "minutes after", - "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", - "Monday": "星期一", - "More": "More", - "MoveLeft": "Move left", - "MoveRight": "Move right", - "Movies": "Movies", - "MySubtitles": "我的字幕", - "Name": "Name", - "NewCollection": "新合集", - "NewCollectionHelp": "收藏櫃讓您能夠建立個人化的影音及其他媒體的分類", - "NewCollectionNameExample": "例子:星球大戰合集", - "NewEpisodes": "New episodes", - "NewEpisodesOnly": "New episodes only", - "News": "News", - "Next": "Next", - "No": "No", - "NoItemsFound": "無項目", - "NoSubtitleSearchResultsFound": "無結果", - "NoSubtitles": "No subtitles", - "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "None": "None", - "Normal": "Normal", - "Off": "Off", - "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", - "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB/IDX, etc.)", - "Open": "Open", - "OptionNew": "新增...", - "Original": "Original", - "OriginalAirDateValue": "原始播出日期:{0}", - "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", - "ParentalRating": "Parental Rating", - "People": "People", - "PerfectMatch": "Perfect match", - "Photos": "Photos", - "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", - "Play": "播放", - "PlayAllFromHere": "Play all from here", - "PlayCount": "Play count", - "PlayFromBeginning": "Play from beginning", - "PlayNext": "Play next", - "PlayNextEpisodeAutomatically": "Play next episode automatically", - "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", - "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", - "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", - "PlaybackSettings": "Playback settings", - "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", - "Played": "Played", - "Playlists": "Playlists", - "PleaseEnterNameOrId": "Please enter a name or an external Id.", - "PleaseRestartServerName": "Please restart Jellyfin Server - {0}.", - "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", - "PleaseSelectTwoItems": "Please select at least two items.", - "Premiere": "Premiere", - "Premieres": "Premieres", - "Previous": "Previous", - "Primary": "Primary", - "PrivacyPolicy": "Privacy policy", - "Producer": "Producer", - "ProductionLocations": "Production locations", - "Programs": "Programs", - "PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Jellyfin Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Jellyfin server settings.", - "Quality": "Quality", - "QueueAllFromHere": "Queue all from here", - "Raised": "Raised", - "RecentlyWatched": "Recently watched", - "Record": "開始錄影", - "RecordSeries": "錄製整個系列", - "RecordingCancelled": "已取消排程錄製", - "RecordingScheduled": "已排程錄製", - "Recordings": "Recordings", - "RefFramesNotSupported": "Number of video reference frames not supported", - "Refresh": "重新整理", - "RefreshDialogHelp": "詳細資料的更新方式會依據Jellyfin的設定及已經啟用的網路服務來進行", - "RefreshMetadata": "Refresh metadata", - "RefreshQueued": "Refresh queued.", - "Reject": "Reject", - "ReleaseDate": "Release date", - "RemoveDownload": "Remove download", - "RemoveFromCollection": "Remove from collection", - "RemoveFromPlaylist": "Remove from playlist", - "RemovingFromDevice": "Removing from device", - "Repeat": "Repeat", - "RepeatAll": "Repeat all", - "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", - "RepeatOne": "Repeat one", - "ReplaceAllMetadata": "取代所有詳細資料", - "ReplaceExistingImages": "取代現有圖片", - "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", - "ResumeAt": "Resume from {0}", - "Retry": "Retry", - "RunAtStartup": "Run at startup", - "Runtime": "Runtime", - "Saturday": "星期六", - "Save": "保存", - "ScanForNewAndUpdatedFiles": "Scan for new and updated files", - "Schedule": "Schedule", - "Screenshot": "Screenshot", - "Screenshots": "Screenshots", - "Search": "搜尋", - "SearchForCollectionInternetMetadata": "在互聯網上搜索媒體圖像和資料", - "SearchForMissingMetadata": "搜尋遺失的詳細資料", - "SearchForSubtitles": "搜尋字幕", - "SearchResults": "Search Results", - "SecondaryAudioNotSupported": "Audio track switching not supported", - "SeriesCancelled": "Series cancelled.", - "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", - "SeriesRecordingScheduled": "已排程錄製整個系列", - "SeriesSettings": "Series settings", - "SeriesYearToPresent": "{0} - Present", - "ServerNameIsRestarting": "Jellyfin Server - {0} is restarting.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is shutting down.", - "ServerUpdateNeeded": "此Jellyfin伺服器需要更新,請至{0}取得最新版本", - "Settings": "Settings", - "SettingsSaved": "Settings saved.", - "Share": "分享", - "ShowIndicatorsFor": "Show indicators for:", - "ShowTitle": "Show title", - "ShowYear": "Show year", - "Shows": "Shows", - "Shuffle": "Shuffle", - "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", - "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", - "Small": "Small", - "SmallCaps": "Small caps", - "Smaller": "Smaller", - "Smart": "Smart", - "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", - "Songs": "Songs", - "Sort": "Sort", - "SortByValue": "Sort by {0}", - "SortChannelsBy": "Sort channels by:", - "SortName": "Sort name", - "Sports": "Sports", - "StatsForNerds": "Stats for nerds", - "StopRecording": "Stop recording", - "Studios": "Studios", - "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", - "SubtitleCodecNotSupported": "Subtitle format not supported", - "SubtitleSettings": "Subtitle settings", - "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app.", - "Subtitles": "字幕", - "Suggestions": "Suggestions", - "Sunday": "星期天", - "Sync": "Sync", - "SyncJobItemStatusCancelled": "Cancelled", - "SyncJobItemStatusConverting": "Converting", - "SyncJobItemStatusFailed": "Failed", - "SyncJobItemStatusQueued": "Queued", - "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", - "SyncJobItemStatusRemovedFromDevice": "Removed from device", - "SyncJobItemStatusSynced": "Downloaded", - "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", - "SyncJobItemStatusTransferring": "Transferring", - "SyncUnwatchedVideosOnly": "Download unwatched videos only", - "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", - "SyncingDots": "Syncing...", - "TV": "TV", - "Tags": "Tags", - "TagsValue": "Tags: {0}", - "TermsOfUse": "Terms of use", - "ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Jellyfin.", - "ThemeSongs": "Theme songs", - "ThemeVideos": "Theme videos", - "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", - "Thumb": "Thumb", - "Thursday": "星期四", - "TrackCount": "{0}個曲目", - "Trailer": "Trailer", - "Trailers": "Trailers", - "Transcoding": "Transcoding", - "TryMultiSelect": "Try Multi-Select", - "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", - "Tuesday": "星期二", - "Uniform": "Uniform", - "UnlockGuide": "解鎖方式", - "Unplayed": "Unplayed", - "Unrated": "Unrated", - "UntilIDelete": "Until I delete", - "UntilSpaceNeeded": "Until space needed", - "Up": "Up", - "Upload": "Upload", - "ValueAlbumCount": "{0} albums", - "ValueDiscNumber": "Disc {0}", - "ValueEpisodeCount": "{0} episodes", - "ValueGameCount": "{0} games", - "ValueMinutes": "{0} min", - "ValueMovieCount": "{0} movies", - "ValueMusicVideoCount": "{0} music videos", - "ValueOneAlbum": "1 album", - "ValueOneEpisode": "1 episode", - "ValueOneGame": "1 game", - "ValueOneItem": "1 item", - "ValueOneMovie": "1 movie", - "ValueOneMusicVideo": "1 music video", - "ValueOneSeries": "1 series", - "ValueOneSong": "1 song", - "ValueSeconds": "{0} seconds", - "ValueSeriesCount": "{0} series", - "ValueSongCount": "{0} songs", - "ValueSpecialEpisodeName": "Special - {0}", - "Vertical": "Vertical", - "VideoBitDepthNotSupported": "Video bit depth not supported", - "VideoCodecNotSupported": "Video codec not supported", - "VideoFramerateNotSupported": "Video framerate not supported", - "VideoLevelNotSupported": "Video level not supported", - "VideoProfileNotSupported": "Video profile not supported", - "VideoRange": "Video range", - "VideoResolutionNotSupported": "Video resolution not supported", - "ViewAlbum": "View album", - "ViewArtist": "View artist", - "VoiceInput": "Voice Input", - "WakeServer": "Wake server", - "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Jellyfin Server. Your machine may need a little more time to wake, or Jellyfin Server may not be actively running on the machine.", - "WakeServerSuccess": "Success!", - "Watched": "Watched", - "Wednesday": "星期三", - "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", - "Writer": "Writer", - "Yes": "Yes" -} + "PlaybackSettings": "Playback settings", + "SubtitleSettings": "Subtitle settings", + "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": "\u5206\u4eab", + "Add": "\u6dfb\u52a0", + "ServerUpdateNeeded": "\u6b64Emby\u4f3a\u670d\u5668\u9700\u8981\u66f4\u65b0\uff0c\u8acb\u81f3{0}\u53d6\u5f97\u6700\u65b0\u7248\u672c", + "LiveTvRequiresUnlock": "Live TV requires an active Emby Premiere subscription.", + "AttributeNew": "New", + "Premiere": "Premiere", + "Live": "Live", + "Repeat": "Repeat", + "TrackCount": "{0}\u500b\u66f2\u76ee", + "ItemCount": "{0}\u500b\u9805\u76ee", + "OriginalAirDateValue": "\u539f\u59cb\u64ad\u51fa\u65e5\u671f\uff1a{0}", + "EndsAtValue": "\u5b8c\u7d50\u65bc{0}", + "HeaderSelectDate": "\u9078\u64c7\u65e5\u671f", + "Watched": "Watched", + "AirDate": "Air date", + "Played": "Played", + "ButtonOk": "\u78ba\u5b9a", + "ButtonCancel": "\u53d6\u6d88", + "AccessRestrictedTryAgainLater": "Access is currently restricted. Please try again later.", + "ButtonGotIt": "\u6211\u77e5\u9053\u4e86", + "ButtonRestart": "Restart", + "RecordingCancelled": "\u5df2\u53d6\u6d88\u6392\u7a0b\u9304\u88fd", + "SeriesCancelled": "Series cancelled.", + "RecordingScheduled": "\u5df2\u6392\u7a0b\u9304\u88fd", + "SeriesRecordingScheduled": "\u5df2\u6392\u7a0b\u9304\u88fd\u6574\u500b\u7cfb\u5217", + "HeaderNewRecording": "\u65b0\u9304\u88fd", + "WakeServer": "Wake server", + "HeaderWakeServer": "Wake Server", + "AttemptingWakeServer": "Attempting to wake server. Please wait...", + "WakeServerSuccess": "Success!", + "HeaderCustomizeHomeScreen": "Customize Home Screen", + "WakeServerError": "Wake On LAN packets were sent to your server machine, but we're unable to connect to your Emby Server. Your machine may need a little more time to wake, or Emby Server may not be actively running on the machine.", + "Sunday": "\u661f\u671f\u5929", + "Monday": "\u661f\u671f\u4e00", + "Tuesday": "\u661f\u671f\u4e8c", + "Wednesday": "\u661f\u671f\u4e09", + "Thursday": "\u661f\u671f\u56db", + "Friday": "\u661f\u671f\u4e94", + "Saturday": "\u661f\u671f\u516d", + "Days": "\u9304\u5f71\u65e5", + "SortByValue": "Sort by {0}", + "LabelSortBy": "Sort by:", + "LabelSortOrder": "Sort order:", + "HeaderPhotoAlbums": "Photo Albums", + "Photos": "Photos", + "HeaderAppearsOn": "Appears On", + "List": "List", + "RecordSeries": "\u9304\u88fd\u6574\u500b\u7cfb\u5217", + "HeaderCinemaMode": "Cinema Mode", + "HeaderCloudSync": "Cloud Sync", + "Downloads": "Downloads", + "HeaderMyDownloads": "My Downloads", + "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.", + "LiveTvFeatureDescription": "Stream Live TV to any Emby app, with a compatible TV tuner device installed on your Emby Server.", + "DvrFeatureDescription": "Schedule individual Live TV recordings, series recordings, and more with Emby DVR.", + "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.", + "HeaderBecomeProjectSupporter": "\u7acb\u5373\u53d6\u5f97", + "MessageActiveSubscriptionRequiredSeriesRecordings": "\u8981\u4f7f\u7528\u81ea\u52d5\u9304\u88fd\u7cfb\u5217\u7684\u529f\u80fd\uff0c\u9700\u8981\u6709\u6548\u7684Emby\u8c6a\u83ef\u7248\u8a02\u95b1", + "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.", + "FeatureRequiresEmbyPremiere": "\u6b64\u529f\u80fd\u9700\u8981\u6709\u6548\u7684Emby\u8c6a\u83ef\u7248\u8a02\u95b1", + "HeaderConvertYourRecordings": "Convert Your Recordings", + "Record": "\u958b\u59cb\u9304\u5f71", + "Save": "\u4fdd\u5b58", + "Edit": "\u7de8\u8f2f", + "Download": "\u4e0b\u8f09", + "Downloaded": "Downloaded", + "Downloading": "Downloading", + "Advanced": "\u9032\u968e", + "Delete": "\u522a\u9664", + "HeaderDeleteItem": "\u522a\u9664\u9805\u76ee", + "ConfirmDeleteItem": "\u522a\u9664\u6b64\u9805\u76ee\u6642\uff0c\u4e5f\u6703\u4e00\u4f75\u5f9e\u6a94\u6848\u7cfb\u7d71\u53ca\u5a92\u9ad4\u6ac3\u4e2d\u522a\u9664\u3002\u78ba\u5b9a\u8981\u522a\u9664\u55ce\uff1f", + "Refresh": "\u91cd\u65b0\u6574\u7406", + "RefreshQueued": "Refresh queued.", + "AddToCollection": "Add to collection", + "HeaderAddToCollection": "Add to Collection", + "NewCollection": "\u65b0\u5408\u96c6", + "LabelCollection": "\u6536\u85cf\u6ac3\uff1a", + "Help": "\u8aaa\u660e", + "LabelDisplayMode": "Display mode:", + "Desktop": "Desktop", + "Mobile": "Mobile \/ Tablet", + "TV": "TV", + "DisplayModeHelp": "Select the type of screen you're running Emby on.", + "LabelDisplayLanguage": "Display language:", + "LabelDisplayLanguageHelp": "Translating Emby is an ongoing project.", + "LearnHowYouCanContribute": "Learn how you can contribute.", + "NewCollectionHelp": "\u6536\u85cf\u6ac3\u8b93\u60a8\u80fd\u5920\u5efa\u7acb\u500b\u4eba\u5316\u7684\u5f71\u97f3\u53ca\u5176\u4ed6\u5a92\u9ad4\u7684\u5206\u985e", + "SearchForCollectionInternetMetadata": "\u5728\u4e92\u806f\u7db2\u4e0a\u641c\u7d22\u5a92\u9ad4\u5716\u50cf\u548c\u8cc7\u6599", + "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Emby Server setup.", + "EnableThemeSongs": "Enable theme songs", + "EnableBackdrops": "Enable backdrops", + "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", + "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", + "EnableThemeVideos": "Enable theme videos", + "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "RunAtStartup": "Run at startup", + "LabelScreensaver": "Screensaver:", + "LabelSoundEffects": "Sound effects:", + "LabelSkin": "Skin:", + "LabelName": "\u540d\u5b57\uff1a", + "NewCollectionNameExample": "\u4f8b\u5b50\uff1a\u661f\u7403\u5927\u6230\u5408\u96c6", + "MessageItemsAdded": "\u5df2\u65b0\u589e\u9805\u76ee", + "OptionNew": "\u65b0\u589e...", + "LabelPlaylist": "\u64ad\u653e\u6e05\u55ae\uff1a", + "AddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "Subtitles": "\u5b57\u5e55", + "LabelTheme": "Theme:", + "LabelDashboardTheme": "Server dashboard theme:", + "SearchForSubtitles": "\u641c\u5c0b\u5b57\u5e55", + "LabelLanguage": "\u8a9e\u8a00\uff1a", + "Search": "\u641c\u5c0b", + "NoSubtitleSearchResultsFound": "\u7121\u7d50\u679c", + "File": "\u6a94\u6848", + "MessageAreYouSureDeleteSubtitles": "\u60a8\u771f\u7684\u8981\u522a\u9664\u9019\u500b\u5b57\u5e55\u6a94\u55ce\uff1f", + "ConfirmDeletion": "\u78ba\u5b9a\u522a\u9664", + "MySubtitles": "\u6211\u7684\u5b57\u5e55", + "MessageDownloadQueued": "\u9700\u8981\u4e0b\u8f09", + "EditSubtitles": "Edit subtitles", + "UnlockGuide": "\u89e3\u9396\u65b9\u5f0f", + "RefreshMetadata": "Refresh metadata", + "ReplaceExistingImages": "\u53d6\u4ee3\u73fe\u6709\u5716\u7247", + "ReplaceAllMetadata": "\u53d6\u4ee3\u6240\u6709\u8a73\u7d30\u8cc7\u6599", + "SearchForMissingMetadata": "\u641c\u5c0b\u907a\u5931\u7684\u8a73\u7d30\u8cc7\u6599", + "LabelRefreshMode": "\u66f4\u65b0\u6a21\u5f0f\uff1a", + "NoItemsFound": "\u7121\u9805\u76ee", + "HeaderSaySomethingLike": "\u8aaa\u9ede\u6771\u897f\uff0c\u50cf\u662f...", + "ButtonTryAgain": "\u91cd\u8a66", + "HeaderYouSaid": "\u60a8\u662f\u6307...", + "MessageWeDidntRecognizeCommand": "\u5f88\u62b1\u6b49\uff0c\u6211\u5011\u7121\u6cd5\u8fa8\u8b58\u6b64\u6307\u4ee4", + "MessageIfYouBlockedVoice": "\u5982\u679c\u60a8\u62d2\u7d55\u7a0b\u5f0f\u4f7f\u7528\u8a9e\u97f3\u8fa8\u8b58\uff0c\u60a8\u5c07\u9700\u8981\u5728\u91cd\u8a66\u4e4b\u524d\u518d\u6b21\u8a2d\u5b9a", + "ValueDiscNumber": "Disc {0}", + "Unrated": "Unrated", + "Favorite": "\u52a0\u5230\u6700\u611b", + "Like": "\u559c\u6b61", + "Dislike": "\u4e0d\u559c\u6b61", + "RefreshDialogHelp": "\u8a73\u7d30\u8cc7\u6599\u7684\u66f4\u65b0\u65b9\u5f0f\u6703\u4f9d\u64daEmby\u7684\u8a2d\u5b9a\u53ca\u5df2\u7d93\u555f\u7528\u7684\u7db2\u8def\u670d\u52d9\u4f86\u9032\u884c", + "Open": "Open", + "Play": "\u64ad\u653e", + "AddToPlayQueue": "Add to play queue", + "Shuffle": "Shuffle", + "Identify": "Identify", + "EditImages": "\u7de8\u8f2f\u5716\u7247", + "EditMetadata": "Edit metadata", + "Convert": "Convert", + "Sync": "Sync", + "InstantMix": "Instant mix", + "ViewAlbum": "View album", + "ViewArtist": "View artist", + "QueueAllFromHere": "Queue all from here", + "PlayAllFromHere": "Play all from here", + "PlayFromBeginning": "Play from beginning", + "ResumeAt": "Resume from {0}", + "RemoveFromPlaylist": "Remove from playlist", + "RemoveFromCollection": "Remove from collection", + "Sort": "Sort", + "Trailer": "Trailer", + "MarkPlayed": "Mark played", + "MarkUnplayed": "Mark unplayed", + "GroupVersions": "Group versions", + "PleaseSelectTwoItems": "Please select at least two items.", + "TryMultiSelect": "Try Multi-Select", + "TryMultiSelectMessage": "To edit multiple media items, just click and hold any poster and select the items you want to manage. Try it!", + "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation", + "MessageConfirmRecordingCancellation": "Cancel recording?", + "Error": "Error", + "VoiceInput": "Voice Input", + "LabelContentType": "Content type:", + "LabelPath": "Path:", + "Playlists": "Playlists", + "LabelTitle": "Title:", + "LabelOriginalTitle": "Original title:", + "LabelSortTitle": "Sort title:", + "LabelDateAdded": "Date added:", + "DateAdded": "Date added", + "DatePlayed": "Date played", + "ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", + "LabelStatus": "Status:", + "LabelArtists": "Artists:", + "LabelArtistsHelp": "Separate multiple using ;", + "HeaderAlbumArtists": "Album Artists", + "LabelAlbumArtists": "Album artists:", + "LabelAlbum": "Album:", + "Artists": "Artists", + "ImdbRating": "IMDb rating", + "CommunityRating": "Community rating", + "LabelCommunityRating": "Community rating:", + "LabelCriticRating": "Critic rating:", + "CriticRating": "Critic rating", + "LabelWebsite": "Website:", + "LabelTagline": "Tagline:", + "LabelOverview": "Overview:", + "LabelShortOverview": "Short overview:", + "LabelReleaseDate": "Release date:", + "LabelYear": "Year:", + "LabelPlaceOfBirth": "Place of birth:", + "Aired": "Aired", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:", + "LabelRuntimeMinutes": "Run time (minutes):", + "LabelParentalRating": "Parental rating:", + "LabelCustomRating": "Custom rating:", + "LabelOriginalAspectRatio": "Original aspect ratio:", + "Label3DFormat": "3D format:", + "FormatValue": "Format: {0}", + "DownloadsValue": "{0} downloads", + "PerfectMatch": "Perfect match", + "EnableExternalVideoPlayers": "Enable external video players", + "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", + "HeaderSpecialEpisodeInfo": "Special Episode Info", + "LabelAirsBeforeSeason": "Airs before season:", + "LabelAirsAfterSeason": "Airs after season:", + "LabelAirsBeforeEpisode": "Airs before episode:", + "HeaderExternalIds": "External Ids:", + "HeaderDisplaySettings": "Display Settings", + "LabelDisplayOrder": "Display order:", + "Display": "Display", + "Countries": "Countries", + "Genres": "Genres", + "Studios": "Studios", + "Tags": "Tags", + "HeaderMetadataSettings": "Metadata Settings", + "People": "People", + "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": "\u570b\u5bb6\uff1a", + "LabelDynamicExternalId": "{0} Id:", + "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", + "LabelDeathDate": "Death date:", + "LabelEndDate": "End date:", + "LabelSeasonNumber": "Season number:", + "LabelEpisodeNumber": "Episode number:", + "LabelTrackNumber": "Track number:", + "LabelNumber": "Number:", + "LabelDiscNumber": "Disc number:", + "LabelParentNumber": "Parent number:", + "SortName": "Sort name", + "ReleaseDate": "Release date", + "Continuing": "\u6301\u7e8c", + "Ended": "\u5b8c\u7d50", + "HeaderEnabledFields": "Enabled Fields", + "HeaderEnabledFieldsHelp": "Uncheck a field to lock it and prevent its data from being changed.", + "Backdrops": "Backdrops", + "Images": "Images", + "Runtime": "Runtime", + "ProductionLocations": "Production locations", + "BirthLocation": "Birth location", + "ParentalRating": "Parental Rating", + "PlayCount": "Play count", + "Name": "Name", + "Overview": "Overview", + "LabelType": "Type:", + "LabelPersonRole": "Role:", + "LabelPersonRoleHelp": "Example: Ice cream truck driver", + "Actor": "Actor", + "Composer": "Composer", + "Director": "Director", + "GuestStar": "Guest star", + "Producer": "Producer", + "Writer": "Writer", + "MessageNoSyncJobsFound": "No downloads found. Create download jobs using the Download buttons found throughout the app.", + "MessageNoDownloadsFound": "No offline downloads. Download your media for offline use by clicking Download throughout the app.", + "InstallingPackage": "Installing {0}", + "PackageInstallCompleted": "{0} installation completed.", + "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} installation cancelled.", + "SeriesYearToPresent": "{0} - Present", + "ValueOneItem": "1 item", + "ValueOneSong": "1 song", + "ValueSongCount": "{0} songs", + "ValueOneMovie": "1 movie", + "ValueMovieCount": "{0} movies", + "ValueOneSeries": "1 series", + "ValueSeriesCount": "{0} series", + "ValueOneEpisode": "1 episode", + "ValueEpisodeCount": "{0} episodes", + "ValueOneGame": "1 game", + "ValueGameCount": "{0} games", + "ValueOneAlbum": "1 album", + "ValueAlbumCount": "{0} albums", + "ValueOneMusicVideo": "1 music video", + "ValueMusicVideoCount": "{0} music videos", + "ValueMinutes": "{0} min", + "Albums": "Albums", + "Songs": "Songs", + "Books": "Books", + "HeaderAudioBooks": "Audio Books", + "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.", + "PleaseEnterNameOrId": "Please enter a name or an external Id.", + "MessageItemSaved": "Item saved.", + "SearchResults": "Search Results", + "ServerNameIsRestarting": "Emby Server - {0} is restarting.", + "ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", + "HeaderDeleteItems": "Delete Items", + "ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?", + "PleaseRestartServerName": "Please restart Emby Server - {0}.", + "LabelSyncJobName": "Sync job name:", + "SyncingDots": "Syncing...", + "ConvertingDots": "Converting...", + "LabelQuality": "Quality:", + "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.", + "DownloadingDots": "Downloading...", + "HeaderSyncRequiresSub": "Downloading requires an active Emby Premiere subscription.", + "LearnMore": "Learn more", + "LabelProfile": "Profile:", + "LabelBitrateMbps": "Bitrate (Mbps):", + "ConvertUnwatchedVideosOnly": "Convert unwatched videos only", + "SyncUnwatchedVideosOnly": "Download unwatched videos only", + "ConvertUnwatchedVideosOnlyHelp": "Only unwatched videos will be converted.", + "SyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be downloaded, and videos will be removed from the device as they are watched.", + "AutomaticallySyncNewContent": "Automatically download new content", + "AutomaticallySyncNewContentHelp": "New content added to this folder will be automatically downloaded to the device.", + "AutomaticallyConvertNewContent": "Automatically convert new content", + "AutomaticallyConvertNewContentHelp": "New content added to this folder will be automatically converted.", + "LabelItemLimit": "Item limit:", + "ConvertItemLimitHelp": "Optional. Set a limit to the number of items that will be converted.", + "DownloadItemLimitHelp": "Optional. Set a limit to the number of items that will be downloaded.", + "PleaseSelectDeviceToSyncTo": "Please select a device to download to.", + "Screenshots": "Screenshots", + "MoveRight": "Move right", + "MoveLeft": "Move left", + "ConfirmDeleteImage": "Delete image?", + "HeaderEditImages": "Edit Images", + "Settings": "Settings", + "ShowIndicatorsFor": "Show indicators for:", + "NewEpisodes": "New episodes", + "Episodes": "Episodes", + "HDPrograms": "HD programs", + "Programs": "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", + "AnyLanguage": "Any language", + "AroundTime": "Around {0}", + "All": "All", + "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": "Don't record 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", + "DefaultErrorMessage": "There was an error processing the request. Please try again later.", + "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}", + "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", + "Items": "Items", + "OneChannel": "One channel", + "ConfirmRemoveDownload": "Remove download?", + "RemoveDownload": "Remove download", + "KeepDownload": "Keep download", + "AddedOnValue": "Added {0}", + "RemovingFromDevice": "Removing from device", + "KeepOnDevice": "Keep on device", + "CancelDownload": "Cancel download", + "SyncJobItemStatusReadyToTransfer": "Ready to Transfer", + "SyncJobItemStatusSyncedMarkForRemoval": "Removing from device", + "SyncJobItemStatusQueued": "Queued", + "SyncJobItemStatusConverting": "Converting", + "SyncJobItemStatusTransferring": "Transferring", + "SyncJobItemStatusSynced": "Downloaded", + "SyncJobItemStatusFailed": "Failed", + "SyncJobItemStatusRemovedFromDevice": "Removed from device", + "SyncJobItemStatusCancelled": "Cancelled", + "Retry": "Retry", + "HeaderMyDevice": "My Device", + "Continue": "Continue", + "ContinueInSecondsValue": "Continue in {0} seconds.", + "HeaderRemoteControl": "Remote Control", + "Disconnect": "Disconnect", + "EnableDisplayMirroring": "Enable display mirroring", + "HeaderPlayOn": "Play On", + "Quality": "Quality", + "Auto": "Auto", + "AndroidUnlockRestoreHelp": "To restore your previous purchase, please ensure you're signed into the device with the same Google (or Amazon) account that originally made the purchase. Make sure the app store is enabled and not restricted by any parental controls, and ensure you have an active internet connection. You'll only have to do this once to restore your previous purchase.", + "AspectRatio": "Aspect ratio", + "Original": "Original", + "Fill": "Fill", + "BestFit": "Best fit", + "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.", + "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your Emby Server administrator for more information.", + "Accept": "Accept", + "Reject": "Reject", + "Connect": "Connect", + "HeaderMyMedia": "My Media", + "HeaderMyMediaSmall": "My Media (small)", + "LatestFromLibrary": "Latest {0}", + "ContinueWatching": "Continue watching", + "HeaderLatestChannelMedia": "Latest Channel Items", + "HeaderContinueWatching": "Continue Watching", + "HeaderContinueListening": "Continue Listening", + "HeaderActiveRecordings": "Active Recordings", + "HeaderLatestRecordings": "Latest Recordings", + "LabelSyncTo": "Sync to:", + "LabelConvertTo": "Convert to:", + "Next": "Next", + "LabelSource": "Source:", + "LabelVersion": "Version:", + "AllLanguages": "All languages", + "Previous": "Previous", + "HeaderNextUp": "Next Up", + "HeaderLatestFrom": "Latest from {0}", + "LabelHomeScreenSectionValue": "Home screen section {0}:", + "SettingsSaved": "Settings saved.", + "None": "None", + "More": "More", + "Up": "Up", + "Down": "Down", + "Home": "Home", + "Favorites": "Favorites", + "HeaderHomeScreen": "Home Screen", + "HeaderLatestChannelItems": "Latest Channel Items", + "HeaderLibraryOrder": "Library Order", + "HideWatchedContentFromLatestMedia": "Hide watched content from latest media", + "HeaderOnNow": "On Now", + "HeaderPlaybackError": "Playback Error", + "PlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.", + "PlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.", + "PlaybackErrorPlaceHolder": "Please insert the disc in order to play this video.", + "Guide": "Guide", + "Suggestions": "Suggestions", + "HeaderFavoriteCollections": "Favorite Collections", + "HeaderFavoritePlaylists": "Favorite Playlists", + "Collections": "Collections", + "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", + "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", + "Folders": "Folders", + "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", + "DisplayInMyMedia": "Display on home screen", + "Shows": "Shows", + "HeaderLibraryFolders": "Library Folders", + "HeaderTermsOfPurchase": "Terms of Purchase", + "PrivacyPolicy": "Privacy policy", + "TermsOfUse": "Terms of use", + "RepeatMode": "Repeat mode", + "RepeatOne": "Repeat one", + "RepeatAll": "Repeat all", + "LabelDefaultScreen": "Default screen:", + "ConfirmEndPlayerSession": "Would you like to shutdown Emby on {0}?", + "Yes": "Yes", + "No": "No", + "LiveTV": "Live TV", + "Schedule": "Schedule", + "Recordings": "Recordings", + "MarkWatched": "Mark watched", + "ScanForNewAndUpdatedFiles": "Scan for new and updated files", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", + "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "StatsForNerds": "Stats for nerds", + "LabelReasonForTranscoding": "Reason for transcoding:", + "DirectPlaying": "Direct playing", + "DirectStreaming": "Direct streaming", + "Transcoding": "Transcoding", + "ContainerBitrateExceedsLimit": "Media bitrate exceeds limit.", + "VideoCodecNotSupported": "Video codec not supported", + "AudioCodecNotSupported": "Audio codec not supported", + "SubtitleCodecNotSupported": "Subtitle format not supported", + "DirectPlayError": "Direct play error", + "ContainerNotSupported": "Container not supported", + "VideoLevelNotSupported": "Video level not supported", + "AudioBitrateNotSupported": "Audio bitrate not supported", + "AudioChannelsNotSupported": "Audio channels not supported", + "VideoResolutionNotSupported": "Video resolution not supported", + "AudioProfileNotSupported": "Audio profile not supported", + "AudioSampleRateNotSupported": "Audio sample rate not supported", + "AnamorphicVideoNotSupported": "Anamorphic video not supported", + "InterlacedVideoNotSupported": "Interlaced video not supported", + "SecondaryAudioNotSupported": "Audio track switching not supported", + "ErrorRemovingEmbyConnectAccount": "There was an error removing the Emby Connect account. Please ensure you have an active internet connection and try again.", + "HeaderEmbyAccountRemoved": "Emby Account Removed", + "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.", + "GuestUserNotFound": "User not found. Please ensure the name is correct and try again, or try entering their email address.", + "ErrorReachingEmbyConnect": "There was an error reaching the Emby Connect server. Please ensure you have an active internet connection and try again.", + "ErrorAddingEmbyConnectAccount1": "There was an error adding the Emby Connect account. Have you created an Emby account? Sign up at {0}.", + "ErrorAddingEmbyConnectAccount2": "If you're still having an issue, please send an email to {0} from the email address used with the Emby account.", + "ErrorAddingGuestAccount1": "There was an error adding the Emby Connect account. Has your guest created an Emby account? They can sign up at {0}.", + "ErrorAddingGuestAccount2": "If you're still having an issue, please send an email to {0}, and include your email address as well as theirs.", + "MessageEmbyAccountAdded": "The Emby account has been added to this user.", + "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.", + "HeaderEmbyAccountAdded": "Emby Account Added", + "LabelSubtitlePlaybackMode": "Subtitle mode:", + "ErrorDeletingItem": "There was an error deleting the item from Emby Server. Please check that Emby Server has write access to the media folder and try again.", + "NoSubtitles": "No subtitles", + "Default": "Default", + "Absolute": "Absolute", + "Smart": "Smart", + "Small": "Small", + "Smaller": "Smaller", + "Medium": "Medium", + "Large": "Large", + "ExtraLarge": "Extra large", + "OnlyForcedSubtitles": "Only forced subtitles", + "AlwaysPlaySubtitles": "Always play subtitles", + "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "SmartSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.", + "HeaderSubtitleSettings": "Subtitle Settings", + "HeaderSubtitleAppearance": "Subtitle Appearance", + "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", + "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", + "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", + "LabelPreferredSubtitleLanguage": "Preferred subtitle language:", + "LabelTextSize": "Text size:", + "TheseSettingsAffectSubtitlesOnThisDevice": "These settings affect subtitles on this device", + "LabelDropShadow": "Drop shadow:", + "LabelTextBackgroundColor": "Text background color:", + "LabelWindowBackgroundColor": "Text background color:", + "LabelFont": "Font:", + "LabelTextColor": "Text color:", + "Raised": "Raised", + "Depressed": "Depressed", + "Uniform": "Uniform", + "DropShadow": "Drop shadow", + "SmallCaps": "Small caps", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS\/SSA).", + "LabelBurnSubtitles": "Burn subtitles:", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB\/IDX, etc.)", + "Normal": "Normal", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB\/IDX, etc.) as well as certain ASS\/SSA subtitles", + "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB\/IDX, etc.)", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", + "HeaderWaitingForWifi": "Waiting for Wifi", + "WifiRequiredToDownload": "A Wifi connection is required to continue downloading.", + "HeaderDownloadSettings": "Download Settings", + "Hide": "Hide", + "HeaderStartNow": "Start Now", + "HeaderNextVideoPlayingInValue": "Next Video Playing in {0}", + "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", + "HeaderSecondsValue": "{0} Seconds", + "AudioBitDepthNotSupported": "Audio bit depth not supported", + "VideoProfileNotSupported": "Video profile not supported", + "VideoFramerateNotSupported": "Video framerate not supported", + "VideoBitDepthNotSupported": "Video bit depth not supported", + "RefFramesNotSupported": "Number of video reference frames not supported", + "ErrorConnectServerUnreachable": "There was an error performing the requested operation. Your server is unable to contact our Emby Connect Server at {0}. Please ensure your server has an active internet connection and that the communications are being allowed by any firewall or security software you have installed.", + "StopRecording": "Stop recording", + "HeaderStopRecording": "Stop Recording", + "ManageRecording": "Manage recording", + "LabelDropImageHere": "Drop image here, or click to browse.", + "MessageFileReadError": "There was an error reading the file. Please try again.", + "Browse": "Browse", + "HeaderUploadImage": "Upload Image", + "HeaderAddUpdateImage": "Add\/Update Image", + "LabelImageType": "Image type:", + "Upload": "Upload", + "Primary": "Primary", + "Art": "Art", + "Backdrop": "Backdrop", + "Banner": "Banner", + "Box": "Box", + "BoxRear": "Box (rear)", + "Disc": "Disc", + "Logo": "Logo", + "Menu": "Menu", + "Screenshot": "Screenshot", + "Thumb": "Thumb", + "ValueSeconds": "{0} seconds", + "HeaderAudioSettings": "Audio Settings", + "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "HeaderVideoQuality": "Video Quality", + "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", + "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", + "PlayNextEpisodeAutomatically": "Play next episode automatically", + "LabelMaxChromecastBitrate": "Chromecast streaming quality:", + "LabelSkipBackLength": "Skip back length:", + "LabelSkipForwardLength": "Skip forward length:", + "EnableCinemaMode": "Enable cinema mode", + "LabelInternetQuality": "Internet quality:", + "HeaderMusicQuality": "Music Quality", + "LabelHomeNetworkQuality": "Home network quality:", + "HeaderLatestMedia": "Latest Media", + "HeaderRestartingEmbyServer": "Restarting Emby Server", + "RestartPleaseWaitMessage": "Please wait while Emby Server shuts down and restarts. This may take a minute or two.", + "PlayNext": "Play next", + "AllowSeasonalThemes": "Allow automatic seasonal themes", + "AllowSeasonalThemesHelp": "If enabled, seasonal themes will occasionally override your theme setting.", + "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "LabelDateTimeLocale": "Date time locale:", + "DirectorValue": "Director: {0}", + "DirectorsValue": "Directors: {0}", + "GenreValue": "Genre: {0}", + "GenresValue": "Genres: {0}", + "LinksValue": "Links: {0}", + "TagsValue": "Tags: {0}", + "LabelAudio": "Audio:", + "LabelVideo": "Video:", + "LabelSubtitles": "Subtitles:", + "Off": "Off", + "ShowTitle": "Show title", + "ShowYear": "Show year", + "Filters": "Filters", + "Unplayed": "Unplayed", + "LabelTVHomeScreen": "TV mode home screen:", + "Horizontal": "Horizontal", + "Vertical": "Vertical", + "GroupBySeries": "Group by series", + "HeaderVideoType": "Video Type", + "HeaderSeriesStatus": "Series Status", + "Features": "Features", + "Trailers": "Trailers", + "Extras": "Extras", + "ThemeSongs": "Theme songs", + "ThemeVideos": "Theme videos", + "HeaderFavoriteMovies": "Favorite Movies", + "HeaderFavoriteShows": "Favorite Shows", + "HeaderFavoriteEpisodes": "Favorite Episodes", + "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoriteGames": "Favorite Games", + "HeaderFavoriteArtists": "Favorite Artists", + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderFavoriteSongs": "Favorite Songs", + "Ascending": "Ascending", + "Descending": "Descending", + "ColorPrimaries": "Color primaries", + "ColorSpace": "Color space", + "ColorTransfer": "Color transfer", + "VideoRange": "Video range", + "SeriesDisplayOrderHelp": "Order episodes by air date, dvd order, or absolute numbering.", + "PlaybackSettingsIntro": "To configure default playback settings, stop video playback, then click your user icon in the top right section of the app.", + "SubtitleSettingsIntro": "To configure default subtitle appearance and language settings, stop video playback, then click your user icon in the top right section of the app." +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.css b/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.css index f6963482d3..c805f54a2c 100644 --- a/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.css +++ b/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.css @@ -1,3 +1,3 @@ -.originalSubtitleFileLabel { - margin-right: 1em +.originalSubtitleFileLabel { + margin-right: 1em; } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.js b/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.js index 65b1a74b6b..4f5047989d 100644 --- a/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.js +++ b/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.js @@ -1,187 +1,526 @@ -define(["dialogHelper", "require", "layoutManager", "globalize", "userSettings", "connectionManager", "loading", "focusManager", "dom", "apphost", "emby-select", "listViewStyle", "paper-icon-button-light", "css!./../formdialog", "material-icons", "css!./subtitleeditor", "emby-button", "flexStyles"], function(dialogHelper, require, layoutManager, globalize, userSettings, connectionManager, loading, focusManager, dom, appHost) { - "use strict"; +define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', 'connectionManager', 'loading', 'focusManager', 'dom', 'apphost', 'emby-select', 'listViewStyle', 'paper-icon-button-light', 'css!./../formdialog', 'material-icons', 'css!./subtitleeditor', 'emby-button', 'flexStyles'], function (dialogHelper, require, layoutManager, globalize, userSettings, connectionManager, loading, focusManager, dom, appHost) { + 'use strict'; + + var currentItem; + var hasChanges; + + function showLocalSubtitles(context, index) { + + loading.show(); + + var subtitleContent = context.querySelector('.subtitleContent'); + subtitleContent.innerHTML = ''; + + var apiClient = connectionManager.getApiClient(currentItem.ServerId); + var url = 'Videos/' + currentItem.Id + '/Subtitles/' + index; + + apiClient.ajax({ + + type: 'GET', + url: url + + }).then(function (result) { + + subtitleContent.innerHTML = result; + + loading.hide(); + }); + } + + function showRemoteSubtitles(context, id) { + + loading.show(); + + var url = 'Providers/Subtitles/Subtitles/' + id; + + ApiClient.get(ApiClient.getUrl(url)).then(function (result) { + + // show result + + loading.hide(); + }); + } function downloadRemoteSubtitles(context, id) { - var url = "Items/" + currentItem.Id + "/RemoteSearch/Subtitles/" + id, - apiClient = connectionManager.getApiClient(currentItem.ServerId); + + var url = 'Items/' + currentItem.Id + '/RemoteSearch/Subtitles/' + id; + + var apiClient = connectionManager.getApiClient(currentItem.ServerId); apiClient.ajax({ + type: "POST", url: apiClient.getUrl(url) - }).then(function() { - hasChanges = !0, require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#MessageDownloadQueued")) - }), focusManager.autoFocus(context) - }) + + }).then(function () { + + hasChanges = true; + + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#MessageDownloadQueued')); + }); + + focusManager.autoFocus(context); + }); } function deleteLocalSubtitle(context, index) { - var msg = globalize.translate("sharedcomponents#MessageAreYouSureDeleteSubtitles"); - require(["confirm"], function(confirm) { + + var msg = globalize.translate('sharedcomponents#MessageAreYouSureDeleteSubtitles'); + + require(['confirm'], function (confirm) { + confirm({ - title: globalize.translate("sharedcomponents#ConfirmDeletion"), + + title: globalize.translate('sharedcomponents#ConfirmDeletion'), text: msg, - confirmText: globalize.translate("sharedcomponents#Delete"), - primary: "cancel" - }).then(function() { + confirmText: globalize.translate('sharedcomponents#Delete'), + primary: 'cancel' + + }).then(function () { + loading.show(); - var itemId = currentItem.Id, - url = "Videos/" + itemId + "/Subtitles/" + index, - apiClient = connectionManager.getApiClient(currentItem.ServerId); + + var itemId = currentItem.Id; + var url = 'Videos/' + itemId + '/Subtitles/' + index; + + var apiClient = connectionManager.getApiClient(currentItem.ServerId); + apiClient.ajax({ + type: "DELETE", url: apiClient.getUrl(url) - }).then(function() { - hasChanges = !0, reload(context, apiClient, itemId) - }) - }) - }) + + }).then(function () { + + hasChanges = true; + reload(context, apiClient, itemId); + + }); + }); + }); } function fillSubtitleList(context, item) { - var streams = item.MediaStreams || [], - subs = streams.filter(function(s) { - return "Subtitle" === s.Type - }), - html = ""; - subs.length && (html += "

    " + globalize.translate("sharedcomponents#MySubtitles") + "

    ", html += "
    ", html += subs.map(function(s) { - var itemHtml = "", - tagName = layoutManager.tv ? "button" : "div", - className = layoutManager.tv && s.Path ? "listItem listItem-border btnDelete" : "listItem listItem-border"; - return layoutManager.tv && (className += " listItem-focusscale listItem-button"), className += " listItem-noborder", itemHtml += "<" + tagName + ' class="' + className + '" data-index="' + s.Index + '">', itemHtml += 'closed_caption', itemHtml += '
    ', itemHtml += "
    ", itemHtml += s.DisplayTitle || "", itemHtml += "
    ", s.Path && (itemHtml += '
    ' + s.Path + "
    "), itemHtml += "", itemHtml += "
    ", layoutManager.tv || s.Path && (itemHtml += ''), itemHtml += "" - }).join(""), html += "
    "); - var elem = context.querySelector(".subtitleList"); - subs.length ? elem.classList.remove("hide") : elem.classList.add("hide"), elem.innerHTML = html + + var streams = item.MediaStreams || []; + + var subs = streams.filter(function (s) { + + return s.Type === 'Subtitle'; + }); + + var html = ''; + + if (subs.length) { + + html += '

    ' + globalize.translate('sharedcomponents#MySubtitles') + '

    '; + + html += '
    '; + + html += subs.map(function (s) { + + var itemHtml = ''; + + var tagName = layoutManager.tv ? 'button' : 'div'; + var className = layoutManager.tv && s.Path ? 'listItem listItem-border btnDelete' : 'listItem listItem-border'; + + if (layoutManager.tv) { + className += ' listItem-focusscale listItem-button'; + } + + className += ' listItem-noborder'; + + itemHtml += '<' + tagName + ' class="' + className + '" data-index="' + s.Index + '">'; + + itemHtml += 'closed_caption'; + + itemHtml += '
    '; + + itemHtml += '
    '; + itemHtml += s.DisplayTitle || ''; + itemHtml += '
    '; + + if (s.Path) { + itemHtml += '
    ' + (s.Path) + '
    '; + } + + itemHtml += ''; + itemHtml += '
    '; + + if (!layoutManager.tv) { + if (s.Path) { + itemHtml += ''; + } + } + + itemHtml += ''; + + return itemHtml; + + }).join(''); + + html += '
    '; + } + + var elem = context.querySelector('.subtitleList'); + + if (subs.length) { + elem.classList.remove('hide'); + } else { + elem.classList.add('hide'); + } + elem.innerHTML = html; + + //('.btnViewSubtitles', elem).on('click', function () { + + // var index = this.getAttribute('data-index'); + + // showLocalSubtitles(context, index); + + //}); } function fillLanguages(context, apiClient, languages) { - var selectLanguage = context.querySelector("#selectLanguage"); - selectLanguage.innerHTML = languages.map(function(l) { - return '" + + var selectLanguage = context.querySelector('#selectLanguage'); + + selectLanguage.innerHTML = languages.map(function (l) { + + return ''; }); - var lastLanguage = userSettings.get("subtitleeditor-language"); - lastLanguage ? selectLanguage.value = lastLanguage : apiClient.getCurrentUser().then(function(user) { - var lang = user.Configuration.SubtitleLanguagePreference; - lang && (selectLanguage.value = lang) - }) + + var lastLanguage = userSettings.get('subtitleeditor-language'); + if (lastLanguage) { + selectLanguage.value = lastLanguage; + } + else { + + apiClient.getCurrentUser().then(function (user) { + + var lang = user.Configuration.SubtitleLanguagePreference; + + if (lang) { + selectLanguage.value = lang; + } + }); + } } function renderSearchResults(context, results) { - var lastProvider = "", - html = ""; - if (!results.length) return context.querySelector(".noSearchResults").classList.remove("hide"), context.querySelector(".subtitleResults").innerHTML = "", void loading.hide(); - context.querySelector(".noSearchResults").classList.add("hide"); - for (var i = 0, length = results.length; i < length; i++) { - var result = results[i], - provider = result.ProviderName; - provider !== lastProvider && (i > 0 && (html += "
    "), html += "

    " + provider + "

    ", layoutManager.tv, html += "
    ", lastProvider = provider); - var tagName = layoutManager.tv ? "button" : "div", - className = layoutManager.tv ? "listItem listItem-border btnOptions" : "listItem listItem-border"; - layoutManager.tv && (className += " listItem-focusscale listItem-button"), html += "<" + tagName + ' class="' + className + '" data-subid="' + result.Id + '">', html += 'closed_caption'; - html += '
    ', html += "
    " + result.Name + "
    ", html += '
    ', result.Format && (html += '' + globalize.translate("sharedcomponents#FormatValue", result.Format) + ""), null != result.DownloadCount && (html += "" + globalize.translate("sharedcomponents#DownloadsValue", result.DownloadCount) + ""), html += "
    ", result.Comment && (html += '
    ' + result.Comment + "
    "), result.IsHashMatch && (html += '
    ' + globalize.translate("sharedcomponents#PerfectMatch") + "
    "), html += "
    ", layoutManager.tv || (html += ''), html += "" + + var lastProvider = ''; + var html = ''; + + if (!results.length) { + + context.querySelector('.noSearchResults').classList.remove('hide'); + context.querySelector('.subtitleResults').innerHTML = ''; + loading.hide(); + return; } - results.length && (html += "
    "), context.querySelector(".subtitleResults").innerHTML = html, loading.hide() + + context.querySelector('.noSearchResults').classList.add('hide'); + + for (var i = 0, length = results.length; i < length; i++) { + + var result = results[i]; + + var provider = result.ProviderName; + + if (provider !== lastProvider) { + + if (i > 0) { + html += '
    '; + } + html += '

    ' + provider + '

    '; + if (layoutManager.tv) { + html += '
    '; + } else { + html += '
    '; + } + lastProvider = provider; + } + + var tagName = layoutManager.tv ? 'button' : 'div'; + var className = layoutManager.tv ? 'listItem listItem-border btnOptions' : 'listItem listItem-border'; + if (layoutManager.tv) { + className += ' listItem-focusscale listItem-button'; + } + + html += '<' + tagName + ' class="' + className + '" data-subid="' + result.Id + '">'; + + html += 'closed_caption'; + + var bodyClass = result.Comment || result.IsHashMatch ? 'three-line' : 'two-line'; + + html += ''; + + if (!layoutManager.tv) { + html += ''; + } + + html += ''; + } + + if (results.length) { + html += '
    '; + } + + var elem = context.querySelector('.subtitleResults'); + elem.innerHTML = html; + + //('.btnViewSubtitle', elem).on('click', function () { + + // var id = this.getAttribute('data-subid'); + // showRemoteSubtitles(context, id); + //}); + + loading.hide(); } function searchForSubtitles(context, language) { - userSettings.set("subtitleeditor-language", language), loading.show(); - var apiClient = connectionManager.getApiClient(currentItem.ServerId), - url = apiClient.getUrl("Items/" + currentItem.Id + "/RemoteSearch/Subtitles/" + language); - apiClient.getJSON(url).then(function(results) { - renderSearchResults(context, results) - }) + + userSettings.set('subtitleeditor-language', language); + + loading.show(); + + var apiClient = connectionManager.getApiClient(currentItem.ServerId); + var url = apiClient.getUrl('Items/' + currentItem.Id + '/RemoteSearch/Subtitles/' + language); + + apiClient.getJSON(url).then(function (results) { + + renderSearchResults(context, results); + }); } function reload(context, apiClient, itemId) { + + context.querySelector('.noSearchResults').classList.add('hide'); + function onGetItem(item) { - currentItem = item, fillSubtitleList(context, item); - var file = item.Path || "", - index = Math.max(file.lastIndexOf("/"), file.lastIndexOf("\\")); - index > -1 && (file = file.substring(index + 1)), file ? (context.querySelector(".pathValue").innerHTML = file, context.querySelector(".originalFile").classList.remove("hide")) : (context.querySelector(".pathValue").innerHTML = "", context.querySelector(".originalFile").classList.add("hide")), loading.hide() + + currentItem = item; + + fillSubtitleList(context, item); + var file = item.Path || ''; + var index = Math.max(file.lastIndexOf('/'), file.lastIndexOf('\\')); + if (index > -1) { + file = file.substring(index + 1); + } + + if (file) { + context.querySelector('.pathValue').innerHTML = file; + context.querySelector('.originalFile').classList.remove('hide'); + } else { + context.querySelector('.pathValue').innerHTML = ''; + context.querySelector('.originalFile').classList.add('hide'); + } + + loading.hide(); + } + + if (typeof itemId === 'string') { + apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(onGetItem); + } + else { + onGetItem(itemId); } - context.querySelector(".noSearchResults").classList.add("hide"), "string" == typeof itemId ? apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(onGetItem) : onGetItem(itemId) } function onSearchSubmit(e) { - var form = this, - lang = form.querySelector("#selectLanguage", form).value; - return searchForSubtitles(dom.parentWithClass(form, "formDialogContent"), lang), e.preventDefault(), !1 + var form = this; + + var lang = form.querySelector('#selectLanguage', form).value; + + searchForSubtitles(dom.parentWithClass(form, 'formDialogContent'), lang); + + e.preventDefault(); + return false; } function onSubtitleListClick(e) { - var btnDelete = dom.parentWithClass(e.target, "btnDelete"); + + var btnDelete = dom.parentWithClass(e.target, 'btnDelete'); if (btnDelete) { - var index = btnDelete.getAttribute("data-index"); - deleteLocalSubtitle(dom.parentWithClass(btnDelete, "subtitleEditorDialog"), index) + var index = btnDelete.getAttribute('data-index'); + var context = dom.parentWithClass(btnDelete, 'subtitleEditorDialog'); + deleteLocalSubtitle(context, index); } } function onSubtitleResultsClick(e) { - var subtitleId, context, btnOptions = dom.parentWithClass(e.target, "btnOptions"); - btnOptions && (subtitleId = btnOptions.getAttribute("data-subid"), context = dom.parentWithClass(btnOptions, "subtitleEditorDialog"), showDownloadOptions(btnOptions, context, subtitleId)); - var btnDownload = dom.parentWithClass(e.target, "btnDownload"); - btnDownload && (subtitleId = btnDownload.getAttribute("data-subid"), context = dom.parentWithClass(btnDownload, "subtitleEditorDialog"), downloadRemoteSubtitles(context, subtitleId)) + + var btnOptions = dom.parentWithClass(e.target, 'btnOptions'); + var subtitleId; + var context; + + if (btnOptions) { + subtitleId = btnOptions.getAttribute('data-subid'); + context = dom.parentWithClass(btnOptions, 'subtitleEditorDialog'); + showDownloadOptions(btnOptions, context, subtitleId); + } + + var btnDownload = dom.parentWithClass(e.target, 'btnDownload'); + if (btnDownload) { + subtitleId = btnDownload.getAttribute('data-subid'); + context = dom.parentWithClass(btnDownload, 'subtitleEditorDialog'); + downloadRemoteSubtitles(context, subtitleId); + } } function showDownloadOptions(button, context, subtitleId) { + var items = []; + items.push({ - name: Globalize.translate("sharedcomponents#Download"), - id: "download" - }), require(["actionsheet"], function(actionsheet) { + name: Globalize.translate('sharedcomponents#Download'), + id: 'download' + }); + + require(['actionsheet'], function (actionsheet) { + actionsheet.show({ items: items, positionTo: button - }).then(function(id) { + + }).then(function (id) { + switch (id) { - case "download": - downloadRemoteSubtitles(context, subtitleId) + + case 'download': + downloadRemoteSubtitles(context, subtitleId); + break; + default: + break; } - }) - }) + }); + + }); } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function showEditorInternal(itemId, serverId, template) { - hasChanges = !1; + + hasChanges = false; + var apiClient = connectionManager.getApiClient(serverId); - return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(item) { + return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'small'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"), dlg.classList.add("subtitleEditorDialog"), dlg.innerHTML = globalize.translateDocument(template, "sharedcomponents"), dlg.querySelector(".originalSubtitleFileLabel").innerHTML = globalize.translate("sharedcomponents#File"), dlg.querySelector(".subtitleSearchForm").addEventListener("submit", onSearchSubmit); - var btnSubmit = dlg.querySelector(".btnSubmit"); - layoutManager.tv ? (centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), dlg.querySelector(".btnSearchSubtitles").classList.add("hide")) : btnSubmit.classList.add("hide"); - var editorContent = dlg.querySelector(".formDialogContent"); - return dlg.querySelector(".subtitleList").addEventListener("click", onSubtitleListClick), dlg.querySelector(".subtitleResults").addEventListener("click", onSubtitleResultsClick), apiClient.getCultures().then(function(languages) { - fillLanguages(editorContent, apiClient, languages) - }), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), new Promise(function(resolve, reject) { - dlg.addEventListener("close", function() { - layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), hasChanges ? resolve() : reject() - }), dialogHelper.open(dlg), reload(editorContent, apiClient, item) - }) - }) + + dlg.classList.add('formDialog'); + dlg.classList.add('subtitleEditorDialog'); + + dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + dlg.querySelector('.originalSubtitleFileLabel').innerHTML = globalize.translate('sharedcomponents#File'); + + dlg.querySelector('.subtitleSearchForm').addEventListener('submit', onSearchSubmit); + + var btnSubmit = dlg.querySelector('.btnSubmit'); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + dlg.querySelector('.btnSearchSubtitles').classList.add('hide'); + } else { + btnSubmit.classList.add('hide'); + } + + var editorContent = dlg.querySelector('.formDialogContent'); + + dlg.querySelector('.subtitleList').addEventListener('click', onSubtitleListClick); + dlg.querySelector('.subtitleResults').addEventListener('click', onSubtitleResultsClick); + + apiClient.getCultures().then(function (languages) { + + fillLanguages(editorContent, apiClient, languages); + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + + return new Promise(function (resolve, reject) { + + dlg.addEventListener('close', function () { + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + if (hasChanges) { + resolve(); + } else { + reject(); + } + }); + + dialogHelper.open(dlg); + + reload(editorContent, apiClient, item); + }); + }); } function showEditor(itemId, serverId) { - return loading.show(), new Promise(function(resolve, reject) { - require(["text!./subtitleeditor.template.html"], function(template) { - showEditorInternal(itemId, serverId, template).then(resolve, reject) - }) - }) + + loading.show(); + + return new Promise(function (resolve, reject) { + + require(['text!./subtitleeditor.template.html'], function (template) { + + showEditorInternal(itemId, serverId, template).then(resolve, reject); + }); + }); + } - var currentItem, hasChanges; + return { show: showEditor - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/subtitlesettings/subtitleappearancehelper.js b/src/bower_components/emby-webcomponents/subtitlesettings/subtitleappearancehelper.js index cfd79fd9fa..588f491a67 100644 --- a/src/bower_components/emby-webcomponents/subtitlesettings/subtitleappearancehelper.js +++ b/src/bower_components/emby-webcomponents/subtitlesettings/subtitleappearancehelper.js @@ -1,211 +1,160 @@ -define([], function() { +define([], function () { "use strict"; function getTextStyles(settings, isCue) { + var list = []; - if (isCue) switch (settings.textSize || "") { - case "smaller": - list.push({ - name: "font-size", - value: ".5em" - }); - break; - case "small": - list.push({ - name: "font-size", - value: ".7em" - }); - break; - case "large": - list.push({ - name: "font-size", - value: "1.3em" - }); - break; - case "larger": - list.push({ - name: "font-size", - value: "1.72em" - }); - break; - case "extralarge": - list.push({ - name: "font-size", - value: "2em" - }); - break; - default: - case "medium": - } else switch (settings.textSize || "") { - case "smaller": - list.push({ - name: "font-size", - value: ".8em" - }); - break; - case "small": - list.push({ - name: "font-size", - value: "inherit" - }); - break; - case "larger": - list.push({ - name: "font-size", - value: "2em" - }); - break; - case "extralarge": - list.push({ - name: "font-size", - value: "2.2em" - }); - break; - case "large": - list.push({ - name: "font-size", - value: "1.72em" - }); - break; - default: - case "medium": - list.push({ - name: "font-size", - value: "1.36em" - }) + + if (isCue) { + switch (settings.textSize || '') { + + case 'smaller': + list.push({ name: 'font-size', value: '.5em' }); + break; + case 'small': + list.push({ name: 'font-size', value: '.7em' }); + break; + case 'large': + list.push({ name: 'font-size', value: '1.3em' }); + break; + case 'larger': + list.push({ name: 'font-size', value: '1.72em' }); + break; + case 'extralarge': + list.push({ name: 'font-size', value: '2em' }); + break; + default: + case 'medium': + break; + } + } else { + switch (settings.textSize || '') { + + case 'smaller': + list.push({ name: 'font-size', value: '.8em' }); + break; + case 'small': + list.push({ name: 'font-size', value: 'inherit' }); + break; + case 'larger': + list.push({ name: 'font-size', value: '2em' }); + break; + case 'extralarge': + list.push({ name: 'font-size', value: '2.2em' }); + break; + case 'large': + list.push({ name: 'font-size', value: '1.72em' }); + break; + default: + case 'medium': + list.push({ name: 'font-size', value: '1.36em' }); + break; + } } - switch (settings.dropShadow || "") { - case "raised": - list.push({ - name: "text-shadow", - value: "-1px -1px white, 0px -1px white, -1px 0px white, 1px 1px black, 0px 1px black, 1px 0px black" - }); + + switch (settings.dropShadow || '') { + + case 'raised': + list.push({ name: 'text-shadow', value: '-1px -1px white, 0px -1px white, -1px 0px white, 1px 1px black, 0px 1px black, 1px 0px black' }); break; - case "depressed": - list.push({ - name: "text-shadow", - value: "1px 1px white, 0px 1px white, 1px 0px white, -1px -1px black, 0px -1px black, -1px 0px black" - }); + case 'depressed': + list.push({ name: 'text-shadow', value: '1px 1px white, 0px 1px white, 1px 0px white, -1px -1px black, 0px -1px black, -1px 0px black' }); break; - case "uniform": - list.push({ - name: "text-shadow", - value: "-1px 0px #000000, 0px 1px #000000, 1px 0px #000000, 0px -1px #000000" - }); + case 'uniform': + list.push({ name: 'text-shadow', value: '-1px 0px #000000, 0px 1px #000000, 1px 0px #000000, 0px -1px #000000' }); break; - case "none": - list.push({ - name: "text-shadow", - value: "none" - }); + case 'none': + list.push({ name: 'text-shadow', value: 'none' }); break; default: - case "dropshadow": - list.push({ - name: "text-shadow", - value: "#000000 0px 0px 7px" - }) + case 'dropshadow': + list.push({ name: 'text-shadow', value: '#000000 0px 0px 7px' }); + break; } - var background = settings.textBackground || "transparent"; - background && list.push({ - name: "background-color", - value: background - }); - var textColor = settings.textColor || "#ffffff"; - switch (textColor && list.push({ - name: "color", - value: textColor - }), settings.font || "") { - case "typewriter": - list.push({ - name: "font-family", - value: '"Courier New",monospace' - }), list.push({ - name: "font-variant", - value: "none" - }); + + var background = settings.textBackground || 'transparent'; + if (background) { + list.push({ name: 'background-color', value: background }); + } + + var textColor = settings.textColor || '#ffffff'; + if (textColor) { + list.push({ name: 'color', value: textColor }); + } + + switch (settings.font || '') { + + case 'typewriter': + list.push({ name: 'font-family', value: '"Courier New",monospace' }); + list.push({ name: 'font-variant', value: 'none' }); break; - case "print": - list.push({ - name: "font-family", - value: "Georgia,Times New Roman,Arial,Helvetica,serif" - }), list.push({ - name: "font-variant", - value: "none" - }); + case 'print': + list.push({ name: 'font-family', value: 'Georgia,Times New Roman,Arial,Helvetica,serif' }); + list.push({ name: 'font-variant', value: 'none' }); break; - case "console": - list.push({ - name: "font-family", - value: "Consolas,Lucida Console,Menlo,Monaco,monospace" - }), list.push({ - name: "font-variant", - value: "none" - }); + case 'console': + list.push({ name: 'font-family', value: 'Consolas,Lucida Console,Menlo,Monaco,monospace' }); + list.push({ name: 'font-variant', value: 'none' }); break; - case "cursive": - list.push({ - name: "font-family", - value: "Lucida Handwriting,Brush Script MT,Segoe Script,cursive,Quintessential,system-ui,-apple-system,BlinkMacSystemFont,sans-serif" - }), list.push({ - name: "font-variant", - value: "none" - }); + case 'cursive': + list.push({ name: 'font-family', value: 'Lucida Handwriting,Brush Script MT,Segoe Script,cursive,Quintessential,system-ui,-apple-system,BlinkMacSystemFont,sans-serif' }); + list.push({ name: 'font-variant', value: 'none' }); break; - case "casual": - list.push({ - name: "font-family", - value: "Gabriola,Segoe Print,Comic Sans MS,Chalkboard,Short Stack,system-ui,-apple-system,BlinkMacSystemFont,sans-serif" - }), list.push({ - name: "font-variant", - value: "none" - }); + case 'casual': + list.push({ name: 'font-family', value: 'Gabriola,Segoe Print,Comic Sans MS,Chalkboard,Short Stack,system-ui,-apple-system,BlinkMacSystemFont,sans-serif' }); + list.push({ name: 'font-variant', value: 'none' }); break; - case "smallcaps": - list.push({ - name: "font-family", - value: "Copperplate Gothic,Copperplate Gothic Bold,Copperplate,system-ui,-apple-system,BlinkMacSystemFont,sans-serif" - }), list.push({ - name: "font-variant", - value: "small-caps" - }); + case 'smallcaps': + list.push({ name: 'font-family', value: 'Copperplate Gothic,Copperplate Gothic Bold,Copperplate,system-ui,-apple-system,BlinkMacSystemFont,sans-serif' }); + list.push({ name: 'font-variant', value: 'small-caps' }); break; default: - list.push({ - name: "font-family", - value: "inherit" - }), list.push({ - name: "font-variant", - value: "none" - }) + list.push({ name: 'font-family', value: 'inherit' }); + list.push({ name: 'font-variant', value: 'none' }); + break; } - return list + + return list; } function getWindowStyles(settings) { - return [] + + return []; } function getStyles(settings, isCue) { + return { text: getTextStyles(settings, isCue), window: getWindowStyles(settings) - } + }; } function applyStyleList(styles, elem) { + + for (var i = 0, length = styles.length; i < length; i++) { + var style = styles[i]; - elem.style[style.name] = style.value + + elem.style[style.name] = style.value; } } function applyStyles(elements, appearanceSettings) { + var styles = getStyles(appearanceSettings); - elements.text && applyStyleList(styles.text, elements.text), elements.window && applyStyleList(styles.window, elements.window) + + if (elements.text) { + applyStyleList(styles.text, elements.text); + } + if (elements.window) { + applyStyleList(styles.window, elements.window); + } } + return { getStyles: getStyles, applyStyles: applyStyles - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/subtitlesettings/subtitlesettings.js b/src/bower_components/emby-webcomponents/subtitlesettings/subtitlesettings.js index 092c806620..00bed79522 100644 --- a/src/bower_components/emby-webcomponents/subtitlesettings/subtitlesettings.js +++ b/src/bower_components/emby-webcomponents/subtitlesettings/subtitlesettings.js @@ -1,100 +1,222 @@ -define(["require", "globalize", "appSettings", "apphost", "focusManager", "loading", "connectionManager", "subtitleAppearanceHelper", "dom", "events", "listViewStyle", "emby-select", "emby-input", "emby-checkbox", "flexStyles"], function(require, globalize, appSettings, appHost, focusManager, loading, connectionManager, subtitleAppearanceHelper, dom, events) { +define(['require', 'globalize', 'appSettings', 'apphost', 'focusManager', 'loading', 'connectionManager', 'subtitleAppearanceHelper', 'dom', 'events', 'listViewStyle', 'emby-select', 'emby-input', 'emby-checkbox', 'flexStyles'], function (require, globalize, appSettings, appHost, focusManager, loading, connectionManager, subtitleAppearanceHelper, dom, events) { "use strict"; function populateLanguages(select, languages) { + var html = ""; - html += ""; + + html += ""; + for (var i = 0, length = languages.length; i < length; i++) { + var culture = languages[i]; - html += "" + + html += ""; } - select.innerHTML = html + + select.innerHTML = html; } function getSubtitleAppearanceObject(context) { + var appearanceSettings = {}; - return appearanceSettings.textSize = context.querySelector("#selectTextSize").value, appearanceSettings.dropShadow = context.querySelector("#selectDropShadow").value, appearanceSettings.font = context.querySelector("#selectFont").value, appearanceSettings.textBackground = context.querySelector("#inputTextBackground").value, appearanceSettings.textColor = context.querySelector("#inputTextColor").value, appearanceSettings + + appearanceSettings.textSize = context.querySelector('#selectTextSize').value; + appearanceSettings.dropShadow = context.querySelector('#selectDropShadow').value; + appearanceSettings.font = context.querySelector('#selectFont').value; + appearanceSettings.textBackground = context.querySelector('#inputTextBackground').value; + appearanceSettings.textColor = context.querySelector('#inputTextColor').value; + + return appearanceSettings; } function loadForm(context, user, userSettings, appearanceSettings, apiClient) { - apiClient.getCultures().then(function(allCultures) { - appHost.supports("subtitleburnsettings") && user.Policy.EnableVideoPlaybackTranscoding && context.querySelector(".fldBurnIn").classList.remove("hide"); - var selectSubtitleLanguage = context.querySelector("#selectSubtitleLanguage"); - populateLanguages(selectSubtitleLanguage, allCultures), selectSubtitleLanguage.value = user.Configuration.SubtitleLanguagePreference || "", context.querySelector("#selectSubtitlePlaybackMode").value = user.Configuration.SubtitleMode || "", context.querySelector("#selectSubtitlePlaybackMode").dispatchEvent(new CustomEvent("change", {})), context.querySelector("#selectTextSize").value = appearanceSettings.textSize || "", context.querySelector("#selectDropShadow").value = appearanceSettings.dropShadow || "", context.querySelector("#inputTextBackground").value = appearanceSettings.textBackground || "transparent", context.querySelector("#inputTextColor").value = appearanceSettings.textColor || "#ffffff", context.querySelector("#selectFont").value = appearanceSettings.font || "", context.querySelector("#selectSubtitleBurnIn").value = appSettings.get("subtitleburnin") || "", onAppearanceFieldChange({ - target: context.querySelector("#selectTextSize") - }), loading.hide() - }) + + apiClient.getCultures().then(function (allCultures) { + + if (appHost.supports('subtitleburnsettings') && user.Policy.EnableVideoPlaybackTranscoding) { + context.querySelector('.fldBurnIn').classList.remove('hide'); + } + + var selectSubtitleLanguage = context.querySelector('#selectSubtitleLanguage'); + + populateLanguages(selectSubtitleLanguage, allCultures); + + selectSubtitleLanguage.value = user.Configuration.SubtitleLanguagePreference || ""; + context.querySelector('#selectSubtitlePlaybackMode').value = user.Configuration.SubtitleMode || ""; + + context.querySelector('#selectSubtitlePlaybackMode').dispatchEvent(new CustomEvent('change', {})); + + context.querySelector('#selectTextSize').value = appearanceSettings.textSize || ''; + context.querySelector('#selectDropShadow').value = appearanceSettings.dropShadow || ''; + context.querySelector('#inputTextBackground').value = appearanceSettings.textBackground || 'transparent'; + context.querySelector('#inputTextColor').value = appearanceSettings.textColor || '#ffffff'; + context.querySelector('#selectFont').value = appearanceSettings.font || ''; + + context.querySelector('#selectSubtitleBurnIn').value = appSettings.get('subtitleburnin') || ''; + + onAppearanceFieldChange({ + target: context.querySelector('#selectTextSize') + }); + + loading.hide(); + }); } function saveUser(context, user, userSettingsInstance, appearanceKey, apiClient) { + var appearanceSettings = userSettingsInstance.getSubtitleAppearanceSettings(appearanceKey); - return appearanceSettings = Object.assign(appearanceSettings, getSubtitleAppearanceObject(context)), userSettingsInstance.setSubtitleAppearanceSettings(appearanceSettings, appearanceKey), user.Configuration.SubtitleLanguagePreference = context.querySelector("#selectSubtitleLanguage").value, user.Configuration.SubtitleMode = context.querySelector("#selectSubtitlePlaybackMode").value, apiClient.updateUserConfiguration(user.Id, user.Configuration) + appearanceSettings = Object.assign(appearanceSettings, getSubtitleAppearanceObject(context)); + + userSettingsInstance.setSubtitleAppearanceSettings(appearanceSettings, appearanceKey); + + user.Configuration.SubtitleLanguagePreference = context.querySelector('#selectSubtitleLanguage').value; + user.Configuration.SubtitleMode = context.querySelector('#selectSubtitlePlaybackMode').value; + + return apiClient.updateUserConfiguration(user.Id, user.Configuration); } function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) { - loading.show(), appSettings.set("subtitleburnin", context.querySelector("#selectSubtitleBurnIn").value), apiClient.getUser(userId).then(function(user) { - saveUser(context, user, userSettings, instance.appearanceKey, apiClient).then(function() { - loading.hide(), enableSaveConfirmation && require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#SettingsSaved")) - }), events.trigger(instance, "saved") - }, function() { - loading.hide() - }) - }) + + loading.show(); + + appSettings.set('subtitleburnin', context.querySelector('#selectSubtitleBurnIn').value); + + apiClient.getUser(userId).then(function (user) { + + saveUser(context, user, userSettings, instance.appearanceKey, apiClient).then(function () { + + loading.hide(); + if (enableSaveConfirmation) { + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#SettingsSaved')); + }); + } + + events.trigger(instance, 'saved'); + + }, function () { + loading.hide(); + }); + }); } function onSubmit(e) { - var self = this, - apiClient = connectionManager.getApiClient(self.options.serverId), - userId = self.options.userId, - userSettings = self.options.userSettings; - return userSettings.setUserInfo(userId, apiClient).then(function() { + + var self = this; + var apiClient = connectionManager.getApiClient(self.options.serverId); + var userId = self.options.userId; + var userSettings = self.options.userSettings; + + userSettings.setUserInfo(userId, apiClient).then(function () { + var enableSaveConfirmation = self.options.enableSaveConfirmation; - save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation) - }), e && e.preventDefault(), !1 + save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation); + }); + + // Disable default form submission + if (e) { + e.preventDefault(); + } + return false; } function onSubtitleModeChange(e) { - for (var view = dom.parentWithClass(e.target, "subtitlesettings"), subtitlesHelp = view.querySelectorAll(".subtitlesHelp"), i = 0, length = subtitlesHelp.length; i < length; i++) subtitlesHelp[i].classList.add("hide"); - view.querySelector(".subtitles" + this.value + "Help").classList.remove("hide") + + var view = dom.parentWithClass(e.target, 'subtitlesettings'); + + var subtitlesHelp = view.querySelectorAll('.subtitlesHelp'); + for (var i = 0, length = subtitlesHelp.length; i < length; i++) { + subtitlesHelp[i].classList.add('hide'); + } + view.querySelector('.subtitles' + this.value + 'Help').classList.remove('hide'); } function onAppearanceFieldChange(e) { - var view = dom.parentWithClass(e.target, "subtitlesettings"), - appearanceSettings = getSubtitleAppearanceObject(view), - elements = { - window: view.querySelector(".subtitleappearance-preview-window"), - text: view.querySelector(".subtitleappearance-preview-text") - }; - subtitleAppearanceHelper.applyStyles(elements, appearanceSettings) + + var view = dom.parentWithClass(e.target, 'subtitlesettings'); + + var appearanceSettings = getSubtitleAppearanceObject(view); + + var elements = { + window: view.querySelector('.subtitleappearance-preview-window'), + text: view.querySelector('.subtitleappearance-preview-text') + }; + + subtitleAppearanceHelper.applyStyles(elements, appearanceSettings); } function embed(options, self) { - require(["text!./subtitlesettings.template.html"], function(template) { - options.element.classList.add("subtitlesettings"), options.element.innerHTML = globalize.translateDocument(template, "sharedcomponents"), options.element.querySelector("form").addEventListener("submit", onSubmit.bind(self)), options.element.querySelector("#selectSubtitlePlaybackMode").addEventListener("change", onSubtitleModeChange), options.element.querySelector("#selectTextSize").addEventListener("change", onAppearanceFieldChange), options.element.querySelector("#selectDropShadow").addEventListener("change", onAppearanceFieldChange), options.element.querySelector("#selectFont").addEventListener("change", onAppearanceFieldChange), options.element.querySelector("#inputTextColor").addEventListener("change", onAppearanceFieldChange), options.element.querySelector("#inputTextBackground").addEventListener("change", onAppearanceFieldChange), options.enableSaveButton && options.element.querySelector(".btnSave").classList.remove("hide"), appHost.supports("subtitleappearancesettings") && options.element.querySelector(".subtitleAppearanceSection").classList.remove("hide"), self.loadData(), options.autoFocus && focusManager.autoFocus(options.element) - }) + + require(['text!./subtitlesettings.template.html'], function (template) { + + options.element.classList.add('subtitlesettings'); + options.element.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); + + options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self)); + + options.element.querySelector('#selectSubtitlePlaybackMode').addEventListener('change', onSubtitleModeChange); + options.element.querySelector('#selectTextSize').addEventListener('change', onAppearanceFieldChange); + options.element.querySelector('#selectDropShadow').addEventListener('change', onAppearanceFieldChange); + options.element.querySelector('#selectFont').addEventListener('change', onAppearanceFieldChange); + options.element.querySelector('#inputTextColor').addEventListener('change', onAppearanceFieldChange); + options.element.querySelector('#inputTextBackground').addEventListener('change', onAppearanceFieldChange); + + if (options.enableSaveButton) { + options.element.querySelector('.btnSave').classList.remove('hide'); + } + + if (appHost.supports('subtitleappearancesettings')) { + options.element.querySelector('.subtitleAppearanceSection').classList.remove('hide'); + } + + self.loadData(); + + if (options.autoFocus) { + focusManager.autoFocus(options.element); + } + }); } function SubtitleSettings(options) { - this.options = options, embed(options, this) + + this.options = options; + + embed(options, this); } - return SubtitleSettings.prototype.loadData = function() { - var self = this, - context = self.options.element; + + SubtitleSettings.prototype.loadData = function () { + + var self = this; + var context = self.options.element; + loading.show(); - var userId = self.options.userId, - apiClient = connectionManager.getApiClient(self.options.serverId), - userSettings = self.options.userSettings; - apiClient.getUser(userId).then(function(user) { - userSettings.setUserInfo(userId, apiClient).then(function() { - self.dataLoaded = !0; + + var userId = self.options.userId; + var apiClient = connectionManager.getApiClient(self.options.serverId); + var userSettings = self.options.userSettings; + + apiClient.getUser(userId).then(function (user) { + + userSettings.setUserInfo(userId, apiClient).then(function () { + + self.dataLoaded = true; + var appearanceSettings = userSettings.getSubtitleAppearanceSettings(self.options.appearanceKey); - loadForm(context, user, userSettings, appearanceSettings, apiClient) - }) - }) - }, SubtitleSettings.prototype.submit = function() { - onSubmit.call(this) - }, SubtitleSettings.prototype.destroy = function() { - this.options = null - }, SubtitleSettings + + loadForm(context, user, userSettings, appearanceSettings, apiClient); + }); + }); + }; + + SubtitleSettings.prototype.submit = function () { + onSubmit.call(this); + }; + + SubtitleSettings.prototype.destroy = function () { + + this.options = null; + }; + + return SubtitleSettings; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/sync/emby-downloadbutton.js b/src/bower_components/emby-webcomponents/sync/emby-downloadbutton.js index 9c1c37da08..bc91e0333b 100644 --- a/src/bower_components/emby-webcomponents/sync/emby-downloadbutton.js +++ b/src/bower_components/emby-webcomponents/sync/emby-downloadbutton.js @@ -1,71 +1,188 @@ -define(["connectionManager", "serverNotifications", "events", "globalize", "emby-button"], function(connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) { - "use strict"; +define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby-button'], function (connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) { + 'use strict'; function onClick(e) { - var button = this, - id = button.getAttribute("data-id"), - serverId = button.getAttribute("data-serverid"), - apiClient = connectionManager.getApiClient(serverId); - button.classList.contains("downloadbutton-on") ? require(["confirm"], function(confirm) { - confirm({ - text: globalize.translate("sharedcomponents#ConfirmRemoveDownload"), - confirmText: globalize.translate("sharedcomponents#RemoveDownload"), - cancelText: globalize.translate("sharedcomponents#KeepDownload"), - primary: "cancel" - }).then(function() { - apiClient.cancelSyncItems([id]), button.dispatchEvent(new CustomEvent("download-cancel", { - cancelable: !1 - })) - }) - }) : require(["syncDialog"], function(syncDialog) { - syncDialog.showMenu({ - items: [id], - mode: "download", - serverId: serverId - }).then(function() { - button.dispatchEvent(new CustomEvent("download", { - cancelable: !1 - })) - }) - }) + + var button = this; + var id = button.getAttribute('data-id'); + var serverId = button.getAttribute('data-serverid'); + var apiClient = connectionManager.getApiClient(serverId); + + if (!button.classList.contains('downloadbutton-on')) { + + require(['syncDialog'], function (syncDialog) { + syncDialog.showMenu({ + + items: [id], + mode: 'download', + serverId: serverId + + }).then(function () { + + button.dispatchEvent(new CustomEvent('download', { + cancelable: false + })); + + }); + }); + + } else { + + require(['confirm'], function (confirm) { + + confirm({ + + text: globalize.translate('sharedcomponents#ConfirmRemoveDownload'), + confirmText: globalize.translate('sharedcomponents#RemoveDownload'), + cancelText: globalize.translate('sharedcomponents#KeepDownload'), + primary: 'cancel' + + }).then(function () { + apiClient.cancelSyncItems([id]); + + button.dispatchEvent(new CustomEvent('download-cancel', { + cancelable: false + })); + }); + }); + } } function updateSyncStatus(button, syncPercent) { + var icon = button.iconElement; - icon || (button.iconElement = button.querySelector("i"), icon = button.iconElement), null != syncPercent ? (button.classList.add("downloadbutton-on"), icon && icon.classList.add("downloadbutton-icon-on")) : (button.classList.remove("downloadbutton-on"), icon && icon.classList.remove("downloadbutton-icon-on")), (syncPercent || 0) >= 100 ? (button.classList.add("downloadbutton-complete"), icon && icon.classList.add("downloadbutton-icon-complete")) : (button.classList.remove("downloadbutton-complete"), icon && icon.classList.remove("downloadbutton-icon-complete")); + if (!icon) { + button.iconElement = button.querySelector('i'); + icon = button.iconElement; + } + + if (syncPercent != null) { + button.classList.add('downloadbutton-on'); + + if (icon) { + icon.classList.add('downloadbutton-icon-on'); + } + + } else { + button.classList.remove('downloadbutton-on'); + + if (icon) { + icon.classList.remove('downloadbutton-icon-on'); + } + } + + if ((syncPercent || 0) >= 100) { + button.classList.add('downloadbutton-complete'); + + if (icon) { + icon.classList.add('downloadbutton-icon-complete'); + } + } else { + button.classList.remove('downloadbutton-complete'); + + if (icon) { + icon.classList.remove('downloadbutton-icon-complete'); + } + } + var text; - text = (syncPercent || 0) >= 100 ? globalize.translate("sharedcomponents#Downloaded") : null != syncPercent ? globalize.translate("sharedcomponents#Downloading") : globalize.translate("sharedcomponents#Download"); - var textElement = button.querySelector(".emby-downloadbutton-downloadtext"); - textElement && (textElement.innerHTML = text), button.title = text + if ((syncPercent || 0) >= 100) { + text = globalize.translate('sharedcomponents#Downloaded'); + } else if (syncPercent != null) { + text = globalize.translate('sharedcomponents#Downloading'); + } else { + text = globalize.translate('sharedcomponents#Download'); + } + + var textElement = button.querySelector('.emby-downloadbutton-downloadtext'); + if (textElement) { + textElement.innerHTML = text; + } + + button.title = text; } function clearEvents(button) { - button.removeEventListener("click", onClick) + + button.removeEventListener('click', onClick); } function bindEvents(button) { - clearEvents(button), button.addEventListener("click", onClick) + + clearEvents(button); + + button.addEventListener('click', onClick); } - function fetchAndUpdate(button, item) { - connectionManager.getApiClient(item.ServerId).getSyncStatus(item.Id).then(function(result) { - updateSyncStatus(button, result.Progress) - }, function() {}) - } var EmbyDownloadButtonPrototype = Object.create(EmbyButtonPrototype); - EmbyDownloadButtonPrototype.createdCallback = function() { - EmbyButtonPrototype.createdCallback && EmbyButtonPrototype.createdCallback.call(this) - }, EmbyDownloadButtonPrototype.attachedCallback = function() { - EmbyButtonPrototype.attachedCallback && EmbyButtonPrototype.attachedCallback.call(this); - var itemId = this.getAttribute("data-id"), - serverId = this.getAttribute("data-serverid"); - itemId && serverId && bindEvents(this) - }, EmbyDownloadButtonPrototype.detachedCallback = function() { - EmbyButtonPrototype.detachedCallback && EmbyButtonPrototype.detachedCallback.call(this), clearEvents(this), this.iconElement = null - }, EmbyDownloadButtonPrototype.setItem = function(item) { - item ? (this.setAttribute("data-id", item.Id), this.setAttribute("data-serverid", item.ServerId), fetchAndUpdate(this, item), bindEvents(this)) : (this.removeAttribute("data-id"), this.removeAttribute("data-serverid"), clearEvents(this)) - }, document.registerElement("emby-downloadbutton", { + + EmbyDownloadButtonPrototype.createdCallback = function () { + + // base method + if (EmbyButtonPrototype.createdCallback) { + EmbyButtonPrototype.createdCallback.call(this); + } + }; + + EmbyDownloadButtonPrototype.attachedCallback = function () { + + // base method + if (EmbyButtonPrototype.attachedCallback) { + EmbyButtonPrototype.attachedCallback.call(this); + } + + var itemId = this.getAttribute('data-id'); + var serverId = this.getAttribute('data-serverid'); + if (itemId && serverId) { + + bindEvents(this); + } + }; + + EmbyDownloadButtonPrototype.detachedCallback = function () { + + // base method + if (EmbyButtonPrototype.detachedCallback) { + EmbyButtonPrototype.detachedCallback.call(this); + } + + clearEvents(this); + + this.iconElement = null; + }; + + function fetchAndUpdate(button, item) { + + connectionManager.getApiClient(item.ServerId).getSyncStatus(item.Id).then(function (result) { + + updateSyncStatus(button, result.Progress); + + }, function () { + + }); + } + + EmbyDownloadButtonPrototype.setItem = function (item) { + + if (item) { + + this.setAttribute('data-id', item.Id); + this.setAttribute('data-serverid', item.ServerId); + + fetchAndUpdate(this, item); + + bindEvents(this); + + } else { + + this.removeAttribute('data-id'); + this.removeAttribute('data-serverid'); + clearEvents(this); + } + }; + + document.registerElement('emby-downloadbutton', { prototype: EmbyDownloadButtonPrototype, - extends: "button" - }) + extends: 'button' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/sync/sync.js b/src/bower_components/emby-webcomponents/sync/sync.js index a50370da8c..c57fc5255a 100644 --- a/src/bower_components/emby-webcomponents/sync/sync.js +++ b/src/bower_components/emby-webcomponents/sync/sync.js @@ -1,295 +1,736 @@ -define(["apphost", "globalize", "connectionManager", "layoutManager", "focusManager", "scrollHelper", "appSettings", "registrationServices", "dialogHelper", "paper-icon-button-light", "formDialogStyle"], function(appHost, globalize, connectionManager, layoutManager, focusManager, scrollHelper, appSettings, registrationServices, dialogHelper) { - "use strict"; +define(['apphost', 'globalize', 'connectionManager', 'layoutManager', 'focusManager', 'scrollHelper', 'appSettings', 'registrationServices', 'dialogHelper', 'paper-icon-button-light', 'formDialogStyle'], function (appHost, globalize, connectionManager, layoutManager, focusManager, scrollHelper, appSettings, registrationServices, dialogHelper) { + 'use strict'; + + var currentDialogOptions; function submitJob(dlg, apiClient, userId, syncOptions, form) { - if (!userId) throw new Error("userId cannot be null"); - if (!syncOptions) throw new Error("syncOptions cannot be null"); - if (!form) throw new Error("form cannot be null"); - var selectSyncTarget = form.querySelector("#selectSyncTarget"), - target = selectSyncTarget ? selectSyncTarget.value : null; - if (!target) return require(["toast"], function(toast) { - toast(globalize.translate("sharedcomponents#PleaseSelectDeviceToSyncTo")) - }), !1; + + if (!userId) { + throw new Error('userId cannot be null'); + } + + if (!syncOptions) { + throw new Error('syncOptions cannot be null'); + } + + if (!form) { + throw new Error('form cannot be null'); + } + + var selectSyncTarget = form.querySelector('#selectSyncTarget'); + var target = selectSyncTarget ? selectSyncTarget.value : null; + + if (!target) { + + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#PleaseSelectDeviceToSyncTo')); + }); + return false; + } + var options = { + userId: userId, TargetId: target, + ParentId: syncOptions.ParentId, Category: syncOptions.Category }; - return setJobValues(options, form), syncOptions.items && syncOptions.items.length && (options.ItemIds = (syncOptions.items || []).map(function(i) { - return i.Id || i - }).join(",")), apiClient.ajax({ + + setJobValues(options, form); + + if (syncOptions.items && syncOptions.items.length) { + options.ItemIds = (syncOptions.items || []).map(function (i) { + return i.Id || i; + }).join(','); + } + + apiClient.ajax({ + type: "POST", url: apiClient.getUrl("Sync/Jobs"), data: JSON.stringify(options), contentType: "application/json", - dataType: "json" - }).then(function() { - dialogHelper.close(dlg), require(["toast"], function(toast) { - showSubmissionToast(target, apiClient), "download" === syncOptions.mode && syncNow() - }) - }), !0 + dataType: 'json' + + }).then(function () { + + dialogHelper.close(dlg); + require(['toast'], function (toast) { + + showSubmissionToast(target, apiClient); + + if (syncOptions.mode === 'download') { + syncNow(); + } + }); + }); + + return true; } + function showSubmissionToast(targetId, apiClient) { - require(["toast"], function(toast) { - toast(targetId === apiClient.deviceId() ? globalize.translate("sharedcomponents#DownloadingDots") : globalize.translate("sharedcomponents#SyncingDots")) - }) + + require(['toast'], function (toast) { + + var msg = targetId === apiClient.deviceId() ? + globalize.translate('sharedcomponents#DownloadingDots') : + globalize.translate('sharedcomponents#SyncingDots'); + + toast(msg); + }); } function syncNow() { - require(["localsync"], function(localSync) { - localSync.sync() - }) + require(['localsync'], function (localSync) { + localSync.sync(); + }); } function submitQuickSyncJob(apiClient, userId, targetId, syncOptions) { - if (!userId) throw new Error("userId cannot be null"); - if (!syncOptions) throw new Error("syncOptions cannot be null"); - if (!targetId) throw new Error("targetId cannot be null"); + + if (!userId) { + throw new Error('userId cannot be null'); + } + + if (!syncOptions) { + throw new Error('syncOptions cannot be null'); + } + + if (!targetId) { + throw new Error('targetId cannot be null'); + } + var options = { + userId: userId, TargetId: targetId, + ParentId: syncOptions.ParentId, Category: syncOptions.Category, Quality: syncOptions.Quality, Bitrate: syncOptions.Bitrate }; - return syncOptions.items && syncOptions.items.length && (options.ItemIds = (syncOptions.items || []).map(function(i) { - return i.Id || i - }).join(",")), apiClient.ajax({ + + if (syncOptions.items && syncOptions.items.length) { + options.ItemIds = (syncOptions.items || []).map(function (i) { + return i.Id || i; + }).join(','); + } + + return apiClient.ajax({ + type: "POST", url: apiClient.getUrl("Sync/Jobs"), data: JSON.stringify(options), contentType: "application/json", - dataType: "json" - }).then(function() { - require(["toast"], function(toast) { - showSubmissionToast(targetId, apiClient), "download" === syncOptions.mode && syncNow() - }) - }) + dataType: 'json' + + }).then(function () { + + require(['toast'], function (toast) { + + showSubmissionToast(targetId, apiClient); + + if (syncOptions.mode === 'download') { + syncNow(); + } + }); + }); } function setJobValues(job, form) { - var txtBitrate = form.querySelector("#txtBitrate"), - bitrate = txtBitrate ? txtBitrate.value : null; - bitrate && (bitrate = 1e6 * parseFloat(bitrate)), job.Bitrate = bitrate; - var selectQuality = form.querySelector("#selectQuality"); - selectQuality && (job.Quality = selectQuality.value, appSettings.set("sync-lastquality", job.Quality || "")); - var selectProfile = form.querySelector("#selectProfile"); - selectProfile && (job.Profile = selectProfile.value); - var txtItemLimit = form.querySelector("#txtItemLimit"); - txtItemLimit && (job.ItemLimit = txtItemLimit.value || null); - var chkSyncNewContent = form.querySelector("#chkSyncNewContent"); - chkSyncNewContent && (job.SyncNewContent = chkSyncNewContent.checked); - var chkUnwatchedOnly = form.querySelector("#chkUnwatchedOnly"); - chkUnwatchedOnly && (job.UnwatchedOnly = chkUnwatchedOnly.checked) + + var txtBitrate = form.querySelector('#txtBitrate'); + var bitrate = txtBitrate ? txtBitrate.value : null; + + if (bitrate) { + bitrate = parseFloat(bitrate) * 1000000; + } + job.Bitrate = bitrate; + + var selectQuality = form.querySelector('#selectQuality'); + if (selectQuality) { + job.Quality = selectQuality.value; + + appSettings.set('sync-lastquality', job.Quality || ''); + } + + var selectProfile = form.querySelector('#selectProfile'); + if (selectProfile) { + job.Profile = selectProfile.value; + } + + var txtItemLimit = form.querySelector('#txtItemLimit'); + if (txtItemLimit) { + job.ItemLimit = txtItemLimit.value || null; + } + + var chkSyncNewContent = form.querySelector('#chkSyncNewContent'); + if (chkSyncNewContent) { + job.SyncNewContent = chkSyncNewContent.checked; + } + + var chkUnwatchedOnly = form.querySelector('#chkUnwatchedOnly'); + if (chkUnwatchedOnly) { + job.UnwatchedOnly = chkUnwatchedOnly.checked; + } } function renderForm(options) { - return new Promise(function(resolve, reject) { - require(["emby-checkbox", "emby-input", "emby-select"], function() { - renderFormInternal(options, connectionManager.deviceId(), resolve) - }) - }) + + return new Promise(function (resolve, reject) { + + require(['emby-checkbox', 'emby-input', 'emby-select'], function () { + + renderFormInternal(options, connectionManager.deviceId(), resolve); + }); + }); } function renderFormInternal(options, defaultTargetId, resolve) { - var elem = options.elem, - dialogOptions = options.dialogOptions, - targets = dialogOptions.Targets, - html = "", - mode = options.mode, - targetContainerClass = "download" === mode ? " hide" : "", - syncTargetLabel = "convert" === mode ? globalize.translate("sharedcomponents#LabelConvertTo") : globalize.translate("sharedcomponents#LabelSyncTo"); - options.readOnlySyncTarget ? (html += '
    ', html += '', html += "
    ") : (html += '
    ', html += '", targets.length || (html += '
    ' + globalize.translate("sharedcomponents#LabelSyncNoTargetsHelp") + "
    "), appHost.supports("externallinks") && (html += '"), html += "
    "), html += '
    ', html += '", html += '
    ', html += "
    ", html += '
    ', html += '", html += '
    ', html += "
    ", html += '
    ', html += '', html += "
    ", -1 !== dialogOptions.Options.indexOf("UnwatchedOnly") && (html += '
    ', html += "", html += "convert" === mode ? '
    ' + globalize.translate("sharedcomponents#ConvertUnwatchedVideosOnlyHelp") + "
    " : '
    ' + globalize.translate("sharedcomponents#SyncUnwatchedVideosOnlyHelp") + "
    ", html += "
    "), -1 !== dialogOptions.Options.indexOf("SyncNewContent") && (html += '
    ', html += "", html += "convert" === mode ? '
    ' + globalize.translate("sharedcomponents#AutomaticallyConvertNewContentHelp") + "
    " : '
    ' + globalize.translate("sharedcomponents#AutomaticallySyncNewContentHelp") + "
    ", html += "
    "), -1 !== dialogOptions.Options.indexOf("ItemLimit") && (html += '
    ', html += '', html += "convert" === mode ? '
    ' + globalize.translate("sharedcomponents#ConvertItemLimitHelp") + "
    " : '
    ' + globalize.translate("sharedcomponents#DownloadItemLimitHelp") + "
    ", html += "
    "), elem.innerHTML = html; - var selectSyncTarget = elem.querySelector("#selectSyncTarget"); - selectSyncTarget && (selectSyncTarget.addEventListener("change", function() { - loadQualityOptions(elem, this.value, options.dialogOptionsFn).then(resolve) - }), selectSyncTarget.dispatchEvent(new CustomEvent("change", { - bubbles: !0 - }))); - var selectProfile = elem.querySelector("#selectProfile"); - selectProfile && (selectProfile.addEventListener("change", function() { - onProfileChange(elem, this.value) - }), dialogOptions.ProfileOptions.length && selectProfile.dispatchEvent(new CustomEvent("change", { - bubbles: !0 - }))); - var selectQuality = elem.querySelector("#selectQuality"); - selectQuality && (selectQuality.addEventListener("change", function() { - onQualityChange(elem, this.value) - }), selectQuality.dispatchEvent(new CustomEvent("change", { - bubbles: !0 - }))), setTimeout(function() { - focusManager.autoFocus(elem) - }, 100) + + var elem = options.elem; + var dialogOptions = options.dialogOptions; + + var targets = dialogOptions.Targets; + + var html = ''; + + var mode = options.mode; + var targetContainerClass = mode === 'download' ? ' hide' : ''; + + var syncTargetLabel = mode === 'convert' ? globalize.translate('sharedcomponents#LabelConvertTo') : globalize.translate('sharedcomponents#LabelSyncTo'); + + if (options.readOnlySyncTarget) { + html += '
    '; + html += ''; + html += '
    '; + } else { + html += '
    '; + html += ''; + if (!targets.length) { + html += '
    ' + globalize.translate('sharedcomponents#LabelSyncNoTargetsHelp') + '
    '; + } + + if (appHost.supports('externallinks')) { + html += ''; + } + html += '
    '; + } + + html += '
    '; + html += ''; + html += '
    '; + html += '
    '; + + html += '
    '; + html += ''; + html += '
    '; + html += '
    '; + + html += '
    '; + html += ''; + html += '
    '; + + if (dialogOptions.Options.indexOf('UnwatchedOnly') !== -1) { + html += '
    '; + html += ''; + + if (mode === 'convert') { + html += '
    ' + globalize.translate('sharedcomponents#ConvertUnwatchedVideosOnlyHelp') + '
    '; + } else { + html += '
    ' + globalize.translate('sharedcomponents#SyncUnwatchedVideosOnlyHelp') + '
    '; + } + + html += '
    '; + } + + if (dialogOptions.Options.indexOf('SyncNewContent') !== -1) { + html += '
    '; + html += ''; + + if (mode === 'convert') { + html += '
    ' + globalize.translate('sharedcomponents#AutomaticallyConvertNewContentHelp') + '
    '; + } else { + html += '
    ' + globalize.translate('sharedcomponents#AutomaticallySyncNewContentHelp') + '
    '; + } + html += '
    '; + } + + if (dialogOptions.Options.indexOf('ItemLimit') !== -1) { + html += '
    '; + html += ''; + + if (mode === 'convert') { + html += '
    ' + globalize.translate('sharedcomponents#ConvertItemLimitHelp') + '
    '; + } else { + html += '
    ' + globalize.translate('sharedcomponents#DownloadItemLimitHelp') + '
    '; + } + + html += '
    '; + } + + //html += '
    '; + //html += ''; + + elem.innerHTML = html; + + var selectSyncTarget = elem.querySelector('#selectSyncTarget'); + if (selectSyncTarget) { + selectSyncTarget.addEventListener('change', function () { + loadQualityOptions(elem, this.value, options.dialogOptionsFn).then(resolve); + }); + selectSyncTarget.dispatchEvent(new CustomEvent('change', { + bubbles: true + })); + } + + var selectProfile = elem.querySelector('#selectProfile'); + if (selectProfile) { + selectProfile.addEventListener('change', function () { + onProfileChange(elem, this.value); + }); + + if (dialogOptions.ProfileOptions.length) { + selectProfile.dispatchEvent(new CustomEvent('change', { + bubbles: true + })); + } + } + + var selectQuality = elem.querySelector('#selectQuality'); + if (selectQuality) { + selectQuality.addEventListener('change', function () { + onQualityChange(elem, this.value); + }); + selectQuality.dispatchEvent(new CustomEvent('change', { + bubbles: true + })); + } + + // This isn't ideal, but allow time for the change handlers above to run + setTimeout(function () { + focusManager.autoFocus(elem); + }, 100); } function showWifiMessage() { - require(["dialog", "appRouter"], function(dialog, appRouter) { + + require(['dialog', 'appRouter'], function (dialog, appRouter) { + var options = { - title: globalize.translate("sharedcomponents#HeaderWaitingForWifi"), - text: globalize.translate("sharedcomponents#WifiRequiredToDownload") - }, - items = []; + + title: globalize.translate('sharedcomponents#HeaderWaitingForWifi'), + text: globalize.translate('sharedcomponents#WifiRequiredToDownload') + }; + + var items = []; + items.push({ - name: options.confirmText || globalize.translate("sharedcomponents#ButtonOk"), - id: "ok", - type: "submit" - }), items.push({ - name: options.cancelText || globalize.translate("sharedcomponents#HeaderDownloadSettings"), - id: "downloadsettings", - type: "cancel" - }), options.buttons = items, dialog(options).then(function(result) { - return "ok" === result ? Promise.resolve() : "downloadsettings" === result ? (appRouter.show(appRouter.getRouteUrl("downloadsettings")), Promise.resolve()) : Promise.reject() - }) - }) + name: options.confirmText || globalize.translate('sharedcomponents#ButtonOk'), + id: 'ok', + type: 'submit' + }); + + items.push({ + name: options.cancelText || globalize.translate('sharedcomponents#HeaderDownloadSettings'), + id: 'downloadsettings', + type: 'cancel' + }); + + options.buttons = items; + + dialog(options).then(function (result) { + + if (result === 'ok') { + return Promise.resolve(); + } + if (result === 'downloadsettings') { + appRouter.show(appRouter.getRouteUrl('downloadsettings')); + return Promise.resolve(); + } + + return Promise.reject(); + }); + }); } function validateNetwork() { - switch (navigator.connection ? navigator.connection.type : null) { - case "cellular": - case "bluetooth": - return showWifiMessage(), !1; + + var network = navigator.connection ? navigator.connection.type : null; + + switch (network) { + + case 'cellular': + case 'bluetooth': + showWifiMessage(); + return false; default: - return !0 + return true; } } function showSyncMenu(options) { - return "download" === options.mode && appSettings.syncOnlyOnWifi() && !validateNetwork() ? Promise.reject() : registrationServices.validateFeature("sync").then(function() { - return showSyncMenuInternal(options) - }) + + if (options.mode === 'download' && appSettings.syncOnlyOnWifi() && !validateNetwork()) { + return Promise.reject(); + } + + return registrationServices.validateFeature('sync').then(function () { + return showSyncMenuInternal(options); + }); } function enableAutoSync(options) { - if ("download" !== options.mode) return !1; + + if (options.mode !== 'download') { + return false; + } + var firstItem = (options.items || [])[0] || {}; - return "Audio" === firstItem.Type || ("MusicAlbum" === firstItem.Type || ("MusicArtist" === firstItem.Type || ("MusicGenre" === firstItem.Type || "Playlist" === firstItem.Type && "Audio" === firstItem.MediaType))) + + if (firstItem.Type === 'Audio') { + return true; + } + if (firstItem.Type === 'MusicAlbum') { + return true; + } + if (firstItem.Type === 'MusicArtist') { + return true; + } + if (firstItem.Type === 'MusicGenre') { + return true; + } + if (firstItem.Type === 'Playlist' && firstItem.MediaType === 'Audio') { + return true; + } + + return false; } function showSyncMenuInternal(options) { - var apiClient = connectionManager.getApiClient(options.serverId), - userId = apiClient.getCurrentUserId(); - if (enableAutoSync(options)) return submitQuickSyncJob(apiClient, userId, apiClient.deviceId(), { - items: options.items, - Quality: "custom", - Bitrate: appSettings.maxStaticMusicBitrate() - }); + + var apiClient = connectionManager.getApiClient(options.serverId); + var userId = apiClient.getCurrentUserId(); + + if (enableAutoSync(options)) { + + return submitQuickSyncJob(apiClient, userId, apiClient.deviceId(), { + items: options.items, + Quality: 'custom', + Bitrate: appSettings.maxStaticMusicBitrate() + }); + } + var dialogOptionsFn = getTargetDialogOptionsFn(apiClient, { UserId: userId, - ItemIds: (options.items || []).map(function(i) { - return i.Id || i - }).join(","), + ItemIds: (options.items || []).map(function (i) { + return i.Id || i; + }).join(','), + ParentId: options.ParentId, Category: options.Category, - IncludeProviders: "convert" === options.mode ? "ConvertSyncProvider" : null, - ExcludeProviders: "convert" === options.mode ? null : "ConvertSyncProvider" + IncludeProviders: options.mode === 'convert' ? 'ConvertSyncProvider' : null, + ExcludeProviders: options.mode === 'convert' ? null : 'ConvertSyncProvider' }); - return dialogOptionsFn().then(function(dialogOptions) { + + return dialogOptionsFn().then(function (dialogOptions) { + currentDialogOptions = dialogOptions; + var dlgElementOptions = { - removeOnClose: !0, - scrollY: !1, - autoFocus: !1 + removeOnClose: true, + scrollY: false, + autoFocus: false }; - layoutManager.tv ? dlgElementOptions.size = "fullscreen" : dlgElementOptions.size = "small"; + + if (layoutManager.tv) { + dlgElementOptions.size = 'fullscreen'; + } else { + dlgElementOptions.size = 'small'; + } + var dlg = dialogHelper.createDialog(dlgElementOptions); - dlg.classList.add("formDialog"); - var html = ""; - html += '
    ', html += '', html += '

    '; - var syncButtonLabel = "download" === options.mode ? globalize.translate("sharedcomponents#Download") : "convert" === options.mode ? globalize.translate("sharedcomponents#Convert") : globalize.translate("sharedcomponents#Sync"); - html += syncButtonLabel, html += "

    ", appHost.supports("externallinks") && (html += 'info' + globalize.translate("sharedcomponents#Help") + ""), html += "
    ", html += '
    ', html += '
    ', html += '
    ', html += '
    ', html += '
    ', html += '", html += "
    ", html += "
    ", html += "
    ", html += "
    ", dlg.innerHTML = html; - var submitted = !1; - dlg.querySelector("form").addEventListener("submit", function(e) { - return submitted = submitJob(dlg, apiClient, userId, options, this), e.preventDefault(), !1 - }), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), layoutManager.tv && scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1); + + dlg.classList.add('formDialog'); + + var html = ''; + html += '
    '; + html += ''; + html += '

    '; + + var syncButtonLabel = options.mode === 'download' ? + globalize.translate('sharedcomponents#Download') : + (options.mode === 'convert' ? globalize.translate('sharedcomponents#Convert') : globalize.translate('sharedcomponents#Sync')); + + html += syncButtonLabel; + html += '

    '; + + if (appHost.supports('externallinks')) { + html += 'info' + globalize.translate('sharedcomponents#Help') + ''; + } + + html += '
    '; + + html += '
    '; + html += '
    '; + + html += '
    '; + + html += '
    '; + + html += '
    '; + + html += ''; + html += '
    '; + + html += '
    '; + + html += '
    '; + html += '
    '; + + dlg.innerHTML = html; + + var submitted = false; + + dlg.querySelector('form').addEventListener('submit', function (e) { + + submitted = submitJob(dlg, apiClient, userId, options, this); + + e.preventDefault(); + return false; + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + dialogHelper.close(dlg); + }); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); + } + var promise = dialogHelper.open(dlg); - return renderForm({ - elem: dlg.querySelector(".formFields"), + + renderForm({ + elem: dlg.querySelector('.formFields'), dialogOptions: dialogOptions, dialogOptionsFn: dialogOptionsFn, mode: options.mode - }), promise.then(function() { - return layoutManager.tv && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), submitted ? Promise.resolve() : Promise.reject() - }) - }) + }); + + return promise.then(function () { + if (layoutManager.tv) { + scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); + } + + if (submitted) { + return Promise.resolve(); + } + return Promise.reject(); + }); + }); } function getTargetDialogOptionsFn(apiClient, query) { - return function(targetId) { - return query.TargetId = targetId, apiClient.getJSON(apiClient.getUrl("Sync/Options", query)) - } + + return function (targetId) { + + query.TargetId = targetId; + return apiClient.getJSON(apiClient.getUrl('Sync/Options', query)); + }; } function setQualityFieldVisible(form, visible) { - var fldQuality = form.querySelector(".fldQuality"), - selectQuality = form.querySelector("#selectQuality"); - visible ? (fldQuality && fldQuality.classList.remove("hide"), selectQuality && selectQuality.removeAttribute("required")) : (fldQuality && fldQuality.classList.add("hide"), selectQuality && selectQuality.removeAttribute("required")) + + var fldQuality = form.querySelector('.fldQuality'); + var selectQuality = form.querySelector('#selectQuality'); + + if (visible) { + if (fldQuality) { + fldQuality.classList.remove('hide'); + } + if (selectQuality) { + //selectQuality.setAttribute('required', 'required'); + + // This is a hack due to what appears to be a edge bug but it shoudln't matter as the list always has selectable items + selectQuality.removeAttribute('required'); + } + } else { + if (fldQuality) { + fldQuality.classList.add('hide'); + } + if (selectQuality) { + selectQuality.removeAttribute('required'); + } + } } function onProfileChange(form, profileId) { - var options = currentDialogOptions || {}, - profileOptions = options.ProfileOptions || []; - if (profileOptions.length) { - var option = profileOptions.filter(function(o) { - return o.Id === profileId - })[0], - qualityOptions = options.QualityOptions || []; - option ? (form.querySelector(".profileDescription").innerHTML = option.Description || "", setQualityFieldVisible(form, qualityOptions.length > 0 && option.EnableQualityOptions && -1 !== options.Options.indexOf("Quality"))) : (form.querySelector(".profileDescription").innerHTML = "", setQualityFieldVisible(form, qualityOptions.length > 0 && -1 !== options.Options.indexOf("Quality"))) + + var options = currentDialogOptions || {}; + + var profileOptions = options.ProfileOptions || []; + + if (!profileOptions.length) { + return; + } + + var option = profileOptions.filter(function (o) { + return o.Id === profileId; + })[0]; + + var qualityOptions = options.QualityOptions || []; + + if (option) { + form.querySelector('.profileDescription').innerHTML = option.Description || ''; + setQualityFieldVisible(form, qualityOptions.length > 0 && option.EnableQualityOptions && options.Options.indexOf('Quality') !== -1); + } else { + form.querySelector('.profileDescription').innerHTML = ''; + setQualityFieldVisible(form, qualityOptions.length > 0 && options.Options.indexOf('Quality') !== -1); } } function onQualityChange(form, qualityId) { - var options = currentDialogOptions || {}, - option = (options.QualityOptions || []).filter(function(o) { - return o.Id === qualityId - })[0], - qualityDescription = form.querySelector(".qualityDescription"); - qualityDescription.innerHTML = option ? option.Description || "" : ""; - var fldBitrate = form.querySelector(".fldBitrate"), - txtBitrate = form.querySelector("#txtBitrate"); - "custom" === qualityId ? (fldBitrate && fldBitrate.classList.remove("hide"), txtBitrate && txtBitrate.setAttribute("required", "required")) : (fldBitrate && fldBitrate.classList.add("hide"), txtBitrate && txtBitrate.removeAttribute("required")) + + var options = currentDialogOptions || {}; + var option = (options.QualityOptions || []).filter(function (o) { + return o.Id === qualityId; + })[0]; + + var qualityDescription = form.querySelector('.qualityDescription'); + + if (option) { + qualityDescription.innerHTML = option.Description || ''; + } else { + qualityDescription.innerHTML = ''; + } + + var fldBitrate = form.querySelector('.fldBitrate'); + var txtBitrate = form.querySelector('#txtBitrate'); + + if (qualityId === 'custom') { + + if (fldBitrate) { + fldBitrate.classList.remove('hide'); + } + if (txtBitrate) { + txtBitrate.setAttribute('required', 'required'); + } + } else { + if (fldBitrate) { + fldBitrate.classList.add('hide'); + } + if (txtBitrate) { + txtBitrate.removeAttribute('required'); + } + } } function renderTargetDialogOptions(form, options) { + currentDialogOptions = options; - var fldProfile = form.querySelector(".fldProfile"), - selectProfile = form.querySelector("#selectProfile"); - options.ProfileOptions.length && -1 !== options.Options.indexOf("Profile") ? (fldProfile && fldProfile.classList.remove("hide"), selectProfile && selectProfile.setAttribute("required", "required")) : (fldProfile && fldProfile.classList.add("hide"), selectProfile && selectProfile.removeAttribute("required")), setQualityFieldVisible(form, options.QualityOptions.length > 0), selectProfile && (selectProfile.innerHTML = options.ProfileOptions.map(function(o) { - var selectedAttribute = o.IsDefault ? ' selected="selected"' : ""; - return '" - }).join(""), selectProfile.dispatchEvent(new CustomEvent("change", { - bubbles: !0 - }))); - var selectQuality = form.querySelector("#selectQuality"); + + var fldProfile = form.querySelector('.fldProfile'); + var selectProfile = form.querySelector('#selectProfile'); + + if (options.ProfileOptions.length && options.Options.indexOf('Profile') !== -1) { + if (fldProfile) { + fldProfile.classList.remove('hide'); + } + if (selectProfile) { + selectProfile.setAttribute('required', 'required'); + } + } else { + if (fldProfile) { + fldProfile.classList.add('hide'); + } + if (selectProfile) { + selectProfile.removeAttribute('required'); + } + } + + setQualityFieldVisible(form, options.QualityOptions.length > 0); + + if (selectProfile) { + selectProfile.innerHTML = options.ProfileOptions.map(function (o) { + + var selectedAttribute = o.IsDefault ? ' selected="selected"' : ''; + return ''; + + }).join(''); + + selectProfile.dispatchEvent(new CustomEvent('change', { + bubbles: true + })); + } + + var selectQuality = form.querySelector('#selectQuality'); if (selectQuality) { - selectQuality.innerHTML = options.QualityOptions.map(function(o) { - var selectedAttribute = o.IsDefault ? ' selected="selected"' : ""; - return '" - }).join(""); - var lastQuality = appSettings.get("sync-lastquality"); - lastQuality && options.QualityOptions.filter(function(i) { - return i.Id === lastQuality - }).length && (selectQuality.value = lastQuality), selectQuality.dispatchEvent(new CustomEvent("change", { - bubbles: !0 - })) + selectQuality.innerHTML = options.QualityOptions.map(function (o) { + + var selectedAttribute = o.IsDefault ? ' selected="selected"' : ''; + return ''; + + }).join(''); + + var lastQuality = appSettings.get('sync-lastquality'); + if (lastQuality && options.QualityOptions.filter(function (i) { + + return i.Id === lastQuality; + + }).length) { + selectQuality.value = lastQuality; + } + + selectQuality.dispatchEvent(new CustomEvent('change', { + bubbles: true + })); } } function loadQualityOptions(form, targetId, dialogOptionsFn) { - return dialogOptionsFn(targetId).then(function(options) { - return renderTargetDialogOptions(form, options) - }) + + return dialogOptionsFn(targetId).then(function (options) { + + return renderTargetDialogOptions(form, options); + }); } - var currentDialogOptions; + return { + showMenu: showSyncMenu, renderForm: renderForm, setJobValues: setJobValues - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/sync/syncjobeditor.js b/src/bower_components/emby-webcomponents/sync/syncjobeditor.js index fb8e60d054..c84901bef4 100644 --- a/src/bower_components/emby-webcomponents/sync/syncjobeditor.js +++ b/src/bower_components/emby-webcomponents/sync/syncjobeditor.js @@ -1,221 +1,504 @@ -define(["connectionManager", "serverNotifications", "events", "datetime", "dom", "imageLoader", "loading", "globalize", "apphost", "layoutManager", "scrollHelper", "dialogHelper", "listViewStyle", "paper-icon-button-light", "emby-button", "formDialogStyle", "emby-linkbutton"], function(connectionManager, serverNotifications, events, datetime, dom, imageLoader, loading, globalize, appHost, layoutManager, scrollHelper, dialogHelper) { - "use strict"; +define(['connectionManager', 'serverNotifications', 'events', 'datetime', 'dom', 'imageLoader', 'loading', 'globalize', 'apphost', 'layoutManager', 'scrollHelper', 'dialogHelper', 'listViewStyle', 'paper-icon-button-light', 'emby-button', 'formDialogStyle', 'emby-linkbutton'], function (connectionManager, serverNotifications, events, datetime, dom, imageLoader, loading, globalize, appHost, layoutManager, scrollHelper, dialogHelper) { + 'use strict'; function syncNow() { - require(["localsync"], function(localSync) { - localSync.sync() - }) + require(['localsync'], function (localSync) { + localSync.sync(); + }); } function renderJob(context, job, dialogOptions) { - require(["syncDialog"], function(syncDialog) { + + require(['syncDialog'], function (syncDialog) { syncDialog.renderForm({ - elem: context.querySelector(".syncJobFormContent"), + elem: context.querySelector('.syncJobFormContent'), dialogOptions: dialogOptions, dialogOptionsFn: getTargetDialogOptionsFn(dialogOptions), - readOnlySyncTarget: !0 - }).then(function() { - fillJobValues(context, job, dialogOptions) - }) - }) + readOnlySyncTarget: true + }).then(function () { + fillJobValues(context, job, dialogOptions); + }); + }); } function getTargetDialogOptionsFn(dialogOptions) { - return function(targetId) { - return Promise.resolve(dialogOptions) - } + + return function (targetId) { + + return Promise.resolve(dialogOptions); + }; } function getJobItemHtml(jobItem, apiClient, index) { - var nextAction, html = "", - status = jobItem.Status; - "Failed" === status ? nextAction = "retry" : "Cancelled" === status ? nextAction = "retry" : "Queued" === status || "Transferring" === status || "Converting" === status || "ReadyToTransfer" === status ? nextAction = "cancel" : "Synced" !== status || jobItem.IsMarkedForRemoval || (nextAction = "remove"); - var listItemClass = "listItem listItem-border"; - layoutManager.tv && nextAction && (listItemClass += " btnJobItemMenu"), layoutManager.tv && (listItemClass += " listItem-button"); - var tagName = layoutManager.tv ? "button" : "div"; - html += "<" + tagName + ' type="button" class="' + listItemClass + '" data-itemid="' + jobItem.Id + '" data-status="' + jobItem.Status + '" data-action="' + nextAction + '">'; + + var html = ''; + var status = jobItem.Status; + + var nextAction; + + if (status === 'Failed') { + nextAction = 'retry'; + } + else if (status === 'Cancelled') { + nextAction = 'retry'; + } + else if (status === 'Queued' || status === 'Transferring' || status === 'Converting' || status === 'ReadyToTransfer') { + nextAction = 'cancel'; + } + else if (status === 'Synced' && !jobItem.IsMarkedForRemoval) { + nextAction = 'remove'; + } + + var listItemClass = 'listItem listItem-border'; + if (layoutManager.tv && nextAction) { + listItemClass += ' btnJobItemMenu'; + } + + if (layoutManager.tv) { + listItemClass += ' listItem-button'; + } + + var tagName = layoutManager.tv ? 'button' : 'div'; + html += '<' + tagName + ' type="button" class="' + listItemClass + '" data-itemid="' + jobItem.Id + '" data-status="' + jobItem.Status + '" data-action="' + nextAction + '">'; + var imgUrl; - jobItem.PrimaryImageItemId && (imgUrl = apiClient.getImageUrl(jobItem.PrimaryImageItemId, { - type: "Primary", - width: 80, - tag: jobItem.PrimaryImageTag, - minScale: 1.5 - })), html += imgUrl ? '
    " : 'sync', html += '
    ', html += '

    ', html += jobItem.ItemName, html += "

    ", "Failed" === jobItem.Status ? html += '
    ' : html += '
    ', html += globalize.translate("sharedcomponents#SyncJobItemStatus" + jobItem.Status), "Synced" === jobItem.Status && jobItem.IsMarkedForRemoval && (html += "
    ", html += globalize.translate("sharedcomponents#RemovingFromDevice")), html += "
    ", html += '
    ', html += '
    ', html += "
    ", html += "
    "; - return layoutManager.tv || ("retry" === nextAction ? html += '' : "cancel" === nextAction ? html += '' : "remove" === nextAction && (html += '')), html += "" + + if (jobItem.PrimaryImageItemId) { + + imgUrl = apiClient.getImageUrl(jobItem.PrimaryImageItemId, { + type: "Primary", + width: 80, + tag: jobItem.PrimaryImageTag, + minScale: 1.5 + }); + } + + if (imgUrl) { + html += '
    '; + } + else { + html += 'sync'; + } + + html += '
    '; + + html += '

    '; + html += jobItem.ItemName; + html += '

    '; + + if (jobItem.Status === 'Failed') { + html += '
    '; + } else { + html += '
    '; + } + html += globalize.translate('sharedcomponents#SyncJobItemStatus' + jobItem.Status); + if (jobItem.Status === 'Synced' && jobItem.IsMarkedForRemoval) { + html += '
    '; + html += globalize.translate('sharedcomponents#RemovingFromDevice'); + } + html += '
    '; + + html += '
    '; + html += '
    '; + html += '
    '; + + html += '
    '; + + var moreIcon = ''; + + if (!layoutManager.tv) { + + if (nextAction === 'retry') { + html += ''; + } + else if (nextAction === 'cancel') { + html += ''; + } + else if (nextAction === 'remove') { + html += ''; + } + } + + html += ''; + return html; } function renderJobItems(context, items, apiClient) { - var html = ""; - html += "

    " + globalize.translate("sharedcomponents#Items") + "

    ", html += '
    '; + + var html = ''; + + html += '

    ' + globalize.translate('sharedcomponents#Items') + '

    '; + + html += '
    '; + var index = 0; - html += items.map(function(i) { - return getJobItemHtml(i, apiClient, index++) - }).join(""), html += "
    "; - var elem = context.querySelector(".jobItems"); - elem.innerHTML = html, imageLoader.lazyChildren(elem) + html += items.map(function (i) { + + return getJobItemHtml(i, apiClient, index++); + + }).join(''); + + html += '
    '; + + var elem = context.querySelector('.jobItems'); + elem.innerHTML = html; + imageLoader.lazyChildren(elem); } function parentWithClass(elem, className) { - for (; !elem.classList || !elem.classList.contains(className);) - if (!(elem = elem.parentNode)) return null; - return elem + + while (!elem.classList || !elem.classList.contains(className)) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; } function showJobItemMenu(elem, jobId, apiClient) { - var action = elem.getAttribute("data-action"), - context = parentWithClass(elem, "formDialog"), - listItem = parentWithClass(elem, "listItem"), - jobItemId = listItem.getAttribute("data-itemid"); - "retry" === action ? retryJobItem(context, jobId, jobItemId, apiClient) : "cancel" !== action && "remove" !== action || cancelJobItem(context, jobId, jobItemId, apiClient) + + var action = elem.getAttribute('data-action'); + var context = parentWithClass(elem, 'formDialog'); + var listItem = parentWithClass(elem, 'listItem'); + var jobItemId = listItem.getAttribute('data-itemid'); + + var menuItems = []; + + if (action === 'retry') { + retryJobItem(context, jobId, jobItemId, apiClient); + } + else if (action === 'cancel' || action === 'remove') { + cancelJobItem(context, jobId, jobItemId, apiClient); + } } function cancelJobItem(context, jobId, jobItemId, apiClient) { - showRemoveConfirm(function() { - loading.show(), apiClient.ajax({ + + showRemoveConfirm(function () { + loading.show(); + + apiClient.ajax({ + type: "DELETE", - url: apiClient.getUrl("Sync/JobItems/" + jobItemId) - }).then(function() { - appHost.supports("sync") && syncNow(), loadJob(context, jobId, apiClient) - }) - }) + url: apiClient.getUrl('Sync/JobItems/' + jobItemId) + + }).then(function () { + + // TODO this should check editor options.mode === 'download' + if (appHost.supports('sync')) { + syncNow(); + } + + loadJob(context, jobId, apiClient); + }); + }); } function retryJobItem(context, jobId, jobItemId, apiClient) { - showRetryConfirm(function() { + + showRetryConfirm(function () { apiClient.ajax({ + type: "POST", - url: apiClient.getUrl("Sync/JobItems/" + jobItemId + "/Enable") - }).then(function() { - appHost.supports("sync") && syncNow(), loadJob(context, jobId, apiClient) - }) - }) + url: apiClient.getUrl('Sync/JobItems/' + jobItemId + '/Enable') + + }).then(function () { + + // TODO this should check editor options.mode === 'download' + if (appHost.supports('sync')) { + syncNow(); + } + + loadJob(context, jobId, apiClient); + }); + }); } function showRetryConfirm(callback) { - require(["confirm"], function(confirm) { + + // TODO Implement this as a retry dialog + require(['confirm'], function (confirm) { + confirm({ - text: globalize.translate("sharedcomponents#ConfirmRemoveDownload"), - confirmText: globalize.translate("sharedcomponents#RemoveDownload"), - cancelText: globalize.translate("sharedcomponents#KeepDownload"), - primary: "cancel" - }).then(callback) - }) + + text: globalize.translate('sharedcomponents#ConfirmRemoveDownload'), + confirmText: globalize.translate('sharedcomponents#RemoveDownload'), + cancelText: globalize.translate('sharedcomponents#KeepDownload'), + primary: 'cancel' + + }).then(callback); + }); } function showRemoveConfirm(callback) { - require(["confirm"], function(confirm) { + + require(['confirm'], function (confirm) { + confirm({ - text: globalize.translate("sharedcomponents#ConfirmRemoveDownload"), - confirmText: globalize.translate("sharedcomponents#RemoveDownload"), - cancelText: globalize.translate("sharedcomponents#KeepDownload"), - primary: "cancel" - }).then(callback) - }) + + text: globalize.translate('sharedcomponents#ConfirmRemoveDownload'), + confirmText: globalize.translate('sharedcomponents#RemoveDownload'), + cancelText: globalize.translate('sharedcomponents#KeepDownload'), + primary: 'cancel' + + }).then(callback); + }); + } + + function showConfirm(text, callback) { + + require(['confirm'], function (confirm) { + + confirm(text).then(callback); + }); } function fillJobValues(context, job, editOptions) { - var selectProfile = context.querySelector("#selectProfile"); - selectProfile && (selectProfile.value = job.Profile || ""); - var selectQuality = context.querySelector("#selectQuality"); - selectQuality && (selectQuality.value = job.Quality || ""); - var chkUnwatchedOnly = context.querySelector("#chkUnwatchedOnly"); - chkUnwatchedOnly && (chkUnwatchedOnly.checked = job.UnwatchedOnly); - var chkSyncNewContent = context.querySelector("#chkSyncNewContent"); - chkSyncNewContent && (chkSyncNewContent.checked = job.SyncNewContent); - var txtItemLimit = context.querySelector("#txtItemLimit"); - txtItemLimit && (txtItemLimit.value = job.ItemLimit); - var txtBitrate = context.querySelector("#txtBitrate"); - job.Bitrate ? txtBitrate.value = job.Bitrate / 1e6 : txtBitrate.value = ""; - var target = editOptions.Targets.filter(function(t) { - return t.Id === job.TargetId - })[0], - targetName = target ? target.Name : "", - selectSyncTarget = context.querySelector("#selectSyncTarget"); - selectSyncTarget && (selectSyncTarget.value = targetName) + + var selectProfile = context.querySelector('#selectProfile'); + if (selectProfile) { + selectProfile.value = job.Profile || ''; + } + + var selectQuality = context.querySelector('#selectQuality'); + if (selectQuality) { + selectQuality.value = job.Quality || ''; + } + + var chkUnwatchedOnly = context.querySelector('#chkUnwatchedOnly'); + if (chkUnwatchedOnly) { + chkUnwatchedOnly.checked = job.UnwatchedOnly; + } + + var chkSyncNewContent = context.querySelector('#chkSyncNewContent'); + if (chkSyncNewContent) { + chkSyncNewContent.checked = job.SyncNewContent; + } + + var txtItemLimit = context.querySelector('#txtItemLimit'); + if (txtItemLimit) { + txtItemLimit.value = job.ItemLimit; + } + + var txtBitrate = context.querySelector('#txtBitrate'); + if (job.Bitrate) { + txtBitrate.value = job.Bitrate / 1000000; + } else { + txtBitrate.value = ''; + } + + var target = editOptions.Targets.filter(function (t) { + return t.Id === job.TargetId; + })[0]; + var targetName = target ? target.Name : ''; + + var selectSyncTarget = context.querySelector('#selectSyncTarget'); + if (selectSyncTarget) { + selectSyncTarget.value = targetName; + } } + var _jobOptions; function loadJob(context, id, apiClient) { - loading.show(), apiClient.getJSON(apiClient.getUrl("Sync/Jobs/" + id)).then(function(job) { - apiClient.getJSON(apiClient.getUrl("Sync/Options", { + + loading.show(); + + apiClient.getJSON(apiClient.getUrl('Sync/Jobs/' + id)).then(function (job) { + + apiClient.getJSON(apiClient.getUrl('Sync/Options', { + UserId: job.UserId, - ItemIds: job.RequestedItemIds && job.RequestedItemIds.length ? job.RequestedItemIds.join("") : null, + ItemIds: (job.RequestedItemIds && job.RequestedItemIds.length ? job.RequestedItemIds.join('') : null), + ParentId: job.ParentId, Category: job.Category, TargetId: job.TargetId - })).then(function(options) { - _jobOptions = options, renderJob(context, job, options), loading.hide() - }) - }), apiClient.getJSON(apiClient.getUrl("Sync/JobItems", { + + })).then(function (options) { + + _jobOptions = options; + renderJob(context, job, options); + loading.hide(); + }); + }); + + apiClient.getJSON(apiClient.getUrl('Sync/JobItems', { + JobId: id, - AddMetadata: !0 - })).then(function(result) { - renderJobItems(context, result.Items, apiClient), loading.hide() - }) + AddMetadata: true + + })).then(function (result) { + + renderJobItems(context, result.Items, apiClient); + loading.hide(); + }); } function loadJobInfo(context, job, jobItems, apiClient) { - renderJobItems(context, jobItems, apiClient), loading.hide() + + //renderJob(page, job, _jobOptions); + renderJobItems(context, jobItems, apiClient); + loading.hide(); } function saveJob(context, id, apiClient) { - loading.show(), apiClient.getJSON(apiClient.getUrl("Sync/Jobs/" + id)).then(function(job) { - require(["syncDialog"], function(syncDialog) { - syncDialog.setJobValues(job, context), apiClient.ajax({ - url: apiClient.getUrl("Sync/Jobs/" + id), - type: "POST", + + loading.show(); + + apiClient.getJSON(apiClient.getUrl('Sync/Jobs/' + id)).then(function (job) { + + require(['syncDialog'], function (syncDialog) { + syncDialog.setJobValues(job, context); + + apiClient.ajax({ + + url: apiClient.getUrl('Sync/Jobs/' + id), + type: 'POST', data: JSON.stringify(job), contentType: "application/json" - }).then(function() { - appHost.supports("sync") && syncNow(), loading.hide(), dialogHelper.close(context) - }) - }) - }) + + }).then(function () { + + // TODO this should check editor options.mode === 'download' + if (appHost.supports('sync')) { + syncNow(); + } + + loading.hide(); + dialogHelper.close(context); + }); + }); + }); + } function startListening(apiClient, jobId) { + var startParams = "0,1500"; - startParams += "," + jobId, apiClient.sendMessage("SyncJobStart", startParams) + + startParams += "," + jobId; + + apiClient.sendMessage("SyncJobStart", startParams); } function stopListening(apiClient) { - apiClient.sendMessage("SyncJobStop", "") + + apiClient.sendMessage("SyncJobStop", ""); } function bindEvents(context, jobId, apiClient) { - context.querySelector(".jobItems").addEventListener("click", function(e) { - var btnJobItemMenu = dom.parentWithClass(e.target, "btnJobItemMenu"); - btnJobItemMenu && showJobItemMenu(btnJobItemMenu, jobId, apiClient) - }) + context.querySelector('.jobItems').addEventListener('click', function (e) { + var btnJobItemMenu = dom.parentWithClass(e.target, 'btnJobItemMenu'); + if (btnJobItemMenu) { + showJobItemMenu(btnJobItemMenu, jobId, apiClient); + } + }); } function showEditor(options) { - function onSyncJobMessage(e, apiClient, msg) { - loadJobInfo(dlg, msg.Job, msg.JobItems, apiClient) + + var apiClient = connectionManager.getApiClient(options.serverId); + var id = options.jobId; + + var dlgElementOptions = { + removeOnClose: true, + scrollY: false, + autoFocus: false + }; + + if (layoutManager.tv) { + dlgElementOptions.size = 'fullscreen'; + } else { + dlgElementOptions.size = 'medium'; } - var apiClient = connectionManager.getApiClient(options.serverId), - id = options.jobId, - dlgElementOptions = { - removeOnClose: !0, - scrollY: !1, - autoFocus: !1 - }; - layoutManager.tv ? dlgElementOptions.size = "fullscreen" : dlgElementOptions.size = "medium"; + var dlg = dialogHelper.createDialog(dlgElementOptions); - dlg.classList.add("formDialog"); - var html = ""; - html += '
    ', html += '', html += '

    ', html += globalize.translate("sharedcomponents#Sync"), html += "

    ", appHost.supports("externallinks") && (html += 'info' + globalize.translate("sharedcomponents#Help") + ""), html += "
    ", html += '
    ', html += '
    ', html += '
    ', html += '
    ', html += '
    ', html += '
    ', html += '", html += "
    ", html += "
    ", html += "
    ", html += "
    ", dlg.innerHTML = html; - dlg.querySelector("form").addEventListener("submit", function(e) { - return saveJob(dlg, id, apiClient), e.preventDefault(), !1 - }), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), layoutManager.tv && scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1), loadJob(dlg, id, apiClient), bindEvents(dlg, id, apiClient); + + dlg.classList.add('formDialog'); + + var html = ''; + html += '
    '; + html += ''; + html += '

    '; + html += globalize.translate('sharedcomponents#Sync'); + html += '

    '; + + if (appHost.supports('externallinks')) { + html += 'info' + globalize.translate('sharedcomponents#Help') + ''; + } + + html += '
    '; + + html += '
    '; + html += '
    '; + + html += '
    '; + + html += '
    '; + + html += '
    '; + + html += '
    '; + html += ''; + html += '
    '; + + html += '
    '; + + html += '
    '; + html += '
    '; + + dlg.innerHTML = html; + + var submitted = false; + + dlg.querySelector('form').addEventListener('submit', function (e) { + + saveJob(dlg, id, apiClient); + e.preventDefault(); + return false; + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + dialogHelper.close(dlg); + }); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); + } + + function onSyncJobMessage(e, apiClient, msg) { + loadJobInfo(dlg, msg.Job, msg.JobItems, apiClient); + } + + loadJob(dlg, id, apiClient); + bindEvents(dlg, id, apiClient); + var promise = dialogHelper.open(dlg); - return startListening(apiClient, id), events.on(serverNotifications, "SyncJob", onSyncJobMessage), promise.then(function() { - return stopListening(apiClient), events.off(serverNotifications, "SyncJob", onSyncJobMessage), layoutManager.tv && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), Promise.reject() - }) + + startListening(apiClient, id); + events.on(serverNotifications, "SyncJob", onSyncJobMessage); + + return promise.then(function () { + + stopListening(apiClient); + events.off(serverNotifications, "SyncJob", onSyncJobMessage); + + if (layoutManager.tv) { + scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); + } + + if (submitted) { + return Promise.resolve(); + } + return Promise.reject(); + }); } - var _jobOptions; + return { show: showEditor - } + }; + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/sync/syncjoblist.js b/src/bower_components/emby-webcomponents/sync/syncjoblist.js index aa14d247f9..5deaf6ddb9 100644 --- a/src/bower_components/emby-webcomponents/sync/syncjoblist.js +++ b/src/bower_components/emby-webcomponents/sync/syncjoblist.js @@ -1,209 +1,455 @@ -define(["serverNotifications", "events", "loading", "connectionManager", "imageLoader", "dom", "globalize", "registrationServices", "layoutManager", "listViewStyle"], function(serverNotifications, events, loading, connectionManager, imageLoader, dom, globalize, registrationServices, layoutManager) { - "use strict"; +define(['serverNotifications', 'events', 'loading', 'connectionManager', 'imageLoader', 'dom', 'globalize', 'registrationServices', 'layoutManager', 'listViewStyle'], function (serverNotifications, events, loading, connectionManager, imageLoader, dom, globalize, registrationServices, layoutManager) { + 'use strict'; function onSyncJobCreated(e, apiClient, data) { - fetchData(this) + var listInstance = this; + fetchData(listInstance); } - function onSyncJobUpdated(e, apiClient, data) { - refreshJob(this, data) - } + var listInstance = this; + refreshJob(listInstance, data); + } function onSyncJobCancelled(e, apiClient, data) { - fetchData(this) + var listInstance = this; + fetchData(listInstance); } function refreshList(listInstance, jobs) { for (var i = 0, length = jobs.length; i < length; i++) { - refreshJob(listInstance, jobs[i]) + + var job = jobs[i]; + refreshJob(listInstance, job); } } function syncNow() { - require(["localsync"], function(localSync) { - localSync.sync() - }) + require(['localsync'], function (localSync) { + localSync.sync(); + }); } function cancelJob(listInstance, id) { - require(["confirm"], function(confirm) { + + require(['confirm'], function (confirm) { + + var msg = globalize.translate('sharedcomponents#ConfirmRemoveDownload'); + confirm({ - text: globalize.translate("sharedcomponents#ConfirmRemoveDownload"), - primary: "cancel" - }).then(function() { + + text: msg, + primary: 'cancel' + + }).then(function () { + loading.show(); var apiClient = getApiClient(listInstance); + apiClient.ajax({ - url: apiClient.getUrl("Sync/Jobs/" + id), - type: "DELETE" - }).then(function() { - "download" === listInstance.options.mode && syncNow(), fetchData(listInstance) - }) - }) - }) + + url: apiClient.getUrl('Sync/Jobs/' + id), + type: 'DELETE' + + }).then(function () { + + if (listInstance.options.mode === 'download') { + syncNow(); + } + + fetchData(listInstance); + }); + }); + }); } function refreshJob(listInstance, job) { - var listItem = listInstance.options.element.querySelector(".listItem[data-id='" + job.Id + "']"); - listItem && (listItem.querySelector(".jobStatus").innerHTML = getProgressText(job)) + + var listItem = listInstance.options.element.querySelector('.listItem[data-id=\'' + job.Id + '\']'); + + if (!listItem) { + return; + } + + listItem.querySelector('.jobStatus').innerHTML = getProgressText(job); } function getProgressText(job) { + var status = job.Status; - "Completed" === status && (status = "Synced"); - var html = globalize.translate("sharedcomponents#SyncJobItemStatus" + status); - if ("Transferring" === job.Status || "Converting" === job.Status || "Completed" === job.Status) { - html += " "; - var progress = job.Progress || 0; - progress > 0 && progress < 100 && (progress = progress.toFixed(1)), html += progress + "%" + + if (status === 'Completed') { + status = 'Synced'; } - return html + + var html = globalize.translate('sharedcomponents#SyncJobItemStatus' + status); + + if (job.Status === 'Transferring' || job.Status === 'Converting' || job.Status === 'Completed') { + html += ' '; + + var progress = job.Progress || 0; + if (progress > 0 && progress < 100) { + progress = progress.toFixed(1); + } + html += progress + '%'; + } + + return html; } function getSyncJobHtml(listInstance, job, apiClient) { - var html = "", - tagName = layoutManager.tv ? "button" : "div", - typeAttribute = "button" === tagName ? ' type="button"' : "", - listItemClass = "listItem listItem-border"; - layoutManager.tv && (listItemClass += " listItem-button listItem-focusscale", listItemClass += " btnJobMenu"); - var canEdit = (job.ItemCount || 1) > 1 || "Queued" === job.Status; - html += "<" + tagName + typeAttribute + ' class="' + listItemClass + '" data-canedit="' + canEdit + '" data-id="' + job.Id + '" data-status="' + job.Status + '">'; + + var html = ''; + + var tagName = layoutManager.tv ? 'button' : 'div'; + var typeAttribute = tagName === 'button' ? ' type="button"' : ''; + + var listItemClass = 'listItem listItem-border'; + + if (layoutManager.tv) { + listItemClass += ' listItem-button listItem-focusscale'; + + listItemClass += ' btnJobMenu'; + } + + var canEdit = (job.ItemCount || 1) > 1 || job.Status === 'Queued'; + html += '<' + tagName + typeAttribute + ' class="' + listItemClass + '" data-canedit="' + canEdit + '" data-id="' + job.Id + '" data-status="' + job.Status + '">'; + var imgUrl; - job.PrimaryImageItemId && (imgUrl = apiClient.getImageUrl(job.PrimaryImageItemId, { - type: "Primary", - width: 80, - tag: job.PrimaryImageTag, - minScale: 1.5 - })), imgUrl ? (html += '
    ', html += "
    ") : html += 'file_download'; - var textLines = [], - name = job.Name; - job.ParentName && (name += " - " + job.ParentName), textLines.push(name), 1 === job.ItemCount || textLines.push(globalize.translate("sharedcomponents#ItemCount", job.ItemCount)), html += '
    '; - for (var i = 0, length = textLines.length; i < length; i++) 0 === i ? (html += '

    ', html += textLines[i], html += "

    ") : (html += '
    ', html += textLines[i], html += "
    "); - return html += '
    ', html += getProgressText(job), html += "
    ", html += "
    ", layoutManager.tv || (html += canEdit ? '' : ''), html += "" + + if (job.PrimaryImageItemId) { + + imgUrl = apiClient.getImageUrl(job.PrimaryImageItemId, { + type: "Primary", + width: 80, + tag: job.PrimaryImageTag, + minScale: 1.5 + }); + } + + if (imgUrl) { + html += '
    '; + html += '
    '; + } + else { + html += 'file_download'; + } + + var textLines = []; + + var name = job.Name; + + if (job.ParentName) { + name += ' - ' + job.ParentName; + } + + textLines.push(name); + + if (job.ItemCount === 1) { + //textLines.push(globalize.translate('sharedcomponents#ValueOneItem')); + } else { + textLines.push(globalize.translate('sharedcomponents#ItemCount', job.ItemCount)); + } + + html += '
    '; + + for (var i = 0, length = textLines.length; i < length; i++) { + + if (i === 0) { + html += '

    '; + html += textLines[i]; + html += '

    '; + } else { + html += '
    '; + html += textLines[i]; + html += '
    '; + } + } + + html += '
    '; + html += getProgressText(job); + html += '
    '; + + html += '
    '; + + if (!layoutManager.tv) { + + if (canEdit) { + html += ''; + } else { + html += ''; + } + } + + html += ''; + + return html; } function renderList(listInstance, jobs, apiClient) { - if ((new Date).getTime() - listInstance.lastDataLoad < 6e4) return void refreshList(listInstance, jobs); - listInstance.lastDataLoad = (new Date).getTime(); - for (var html = "", lastTargetName = "", mode = listInstance.options.mode, showTargetName = "download" !== mode, hasOpenSection = !1, i = 0, length = jobs.length; i < length; i++) { + + if ((new Date().getTime() - listInstance.lastDataLoad) < 60000) { + refreshList(listInstance, jobs); + return; + } + + listInstance.lastDataLoad = new Date().getTime(); + + var html = ''; + var lastTargetName = ''; + + var mode = listInstance.options.mode; + var showTargetName = mode !== 'download'; + + var hasOpenSection = false; + + for (var i = 0, length = jobs.length; i < length; i++) { + var job = jobs[i]; if (showTargetName) { - var targetName = job.TargetName || "Unknown"; - targetName !== lastTargetName && (lastTargetName && (html += "
    ", html += "
    ", hasOpenSection = !1), lastTargetName = targetName, html += '
    ', html += '
    ', html += '

    ' + targetName + "

    ", html += "
    ", html += '
    ', hasOpenSection = !0) + var targetName = job.TargetName || 'Unknown'; + + if (targetName !== lastTargetName) { + + if (lastTargetName) { + html += '
    '; + html += '
    '; + hasOpenSection = false; + } + + lastTargetName = targetName; + + html += '
    '; + html += '
    '; + + html += '

    ' + targetName + '

    '; + + html += '
    '; + html += '
    '; + hasOpenSection = true; + } } - html += getSyncJobHtml(listInstance, job, apiClient) + + html += getSyncJobHtml(listInstance, job, apiClient); } - hasOpenSection && (html += "
    ", html += "
    "); - var elem = listInstance.options.element.querySelector(".syncJobListContent"); - html || (html = "download" === mode ? '
    ' + globalize.translate("sharedcomponents#MessageNoDownloadsFound") + "
    " : '
    ' + globalize.translate("sharedcomponents#MessageNoSyncJobsFound") + "
    "), elem.innerHTML = html, imageLoader.lazyChildren(elem) + + if (hasOpenSection) { + html += '
    '; + html += '
    '; + } + + var elem = listInstance.options.element.querySelector('.syncJobListContent'); + + if (!html) { + if (mode === 'download') { + html = '
    ' + globalize.translate('sharedcomponents#MessageNoDownloadsFound') + '
    '; + } else { + html = '
    ' + globalize.translate('sharedcomponents#MessageNoSyncJobsFound') + '
    '; + } + } + + elem.innerHTML = html; + + imageLoader.lazyChildren(elem); } function fetchData(listInstance) { - listInstance.lastDataLoad = 0, loading.show(); - var options = {}, - apiClient = getApiClient(listInstance); - return listInstance.options.userId && (options.UserId = listInstance.options.userId), "download" === listInstance.options.mode && (options.TargetId = apiClient.deviceId()), apiClient.getJSON(apiClient.getUrl("Sync/Jobs", options)).then(function(response) { - renderList(listInstance, response.Items, apiClient), loading.hide() - }) + + listInstance.lastDataLoad = 0; + loading.show(); + + var options = {}; + var apiClient = getApiClient(listInstance); + + if (listInstance.options.userId) { + options.UserId = listInstance.options.userId; + } + + if (listInstance.options.mode === 'download') { + options.TargetId = apiClient.deviceId(); + } + + return apiClient.getJSON(apiClient.getUrl('Sync/Jobs', options)).then(function (response) { + + renderList(listInstance, response.Items, apiClient); + loading.hide(); + }); } function getApiClient(listInstance) { - return connectionManager.getApiClient(listInstance.options.serverId) + return connectionManager.getApiClient(listInstance.options.serverId); } function showJobMenu(listInstance, elem) { - var item = dom.parentWithClass(elem, "listItem"), - jobId = item.getAttribute("data-id"), - menuItems = (item.getAttribute("data-status"), []); - "true" === item.getAttribute("data-canedit") && menuItems.push({ - name: globalize.translate("sharedcomponents#Edit"), - id: "edit" - }); - var txt = globalize.translate("sharedcomponents#RemoveDownload"); + + var item = dom.parentWithClass(elem, 'listItem'); + var jobId = item.getAttribute('data-id'); + var status = item.getAttribute('data-status'); + + var menuItems = []; + + if (item.getAttribute('data-canedit') === 'true') { + menuItems.push({ + name: globalize.translate('sharedcomponents#Edit'), + id: 'edit' + }); + } + + var txt = globalize.translate('sharedcomponents#RemoveDownload'); + menuItems.push({ name: txt, - id: "cancel" - }), require(["actionsheet"], function(actionsheet) { + id: 'cancel' + }); + + require(['actionsheet'], function (actionsheet) { + actionsheet.show({ items: menuItems, positionTo: elem, - callback: function(id) { + callback: function (id) { + switch (id) { - case "delete": - case "cancel": + + case 'delete': cancelJob(listInstance, jobId); break; - case "edit": - showJobEditor(listInstance, elem) + case 'cancel': + cancelJob(listInstance, jobId); + break; + case 'edit': + showJobEditor(listInstance, elem); + break; + default: + break; } } - }) - }) + }); + + }); } function onElementClick(e) { - var listInstance = this, - btnJobMenu = dom.parentWithClass(e.target, "btnJobMenu"); - if (btnJobMenu) return void showJobMenu(listInstance, btnJobMenu); - var btnCancelJob = dom.parentWithClass(e.target, "btnCancelJob"); + + var listInstance = this; + + var btnJobMenu = dom.parentWithClass(e.target, 'btnJobMenu'); + if (btnJobMenu) { + showJobMenu(listInstance, btnJobMenu); + return; + } + + var btnCancelJob = dom.parentWithClass(e.target, 'btnCancelJob'); if (btnCancelJob) { - var listItem = dom.parentWithClass(btnCancelJob, "listItem"); + var listItem = dom.parentWithClass(btnCancelJob, 'listItem'); if (listItem) { - cancelJob(listInstance, listItem.getAttribute("data-id")) + var jobId = listItem.getAttribute('data-id'); + cancelJob(listInstance, jobId); } - } else showJobEditor(listInstance, e.target) + return; + } + + showJobEditor(listInstance, e.target); } function showJobEditor(listInstance, elem) { - var listItem = dom.parentWithClass(elem, "listItem"); - if (listItem && "true" === listItem.getAttribute("data-canedit")) { - var jobId = listItem.getAttribute("data-id"); - require(["syncJobEditor"], function(syncJobEditor) { + + var listItem = dom.parentWithClass(elem, 'listItem'); + if (listItem && listItem.getAttribute('data-canedit') === 'true') { + var jobId = listItem.getAttribute('data-id'); + // edit job + require(['syncJobEditor'], function (syncJobEditor) { syncJobEditor.show({ + serverId: listInstance.options.serverId, jobId: jobId, mode: listInstance.options.mode - }).then(function() { - fetchData(listInstance) - }) - }) + + }).then(function () { + fetchData(listInstance); + }); + }); } } function syncJobList(options) { this.options = options; + var onSyncJobCreatedHandler = onSyncJobCreated.bind(this); - this.onSyncJobCreatedHandler = onSyncJobCreatedHandler, events.on(serverNotifications, "SyncJobCreated", onSyncJobCreatedHandler); + this.onSyncJobCreatedHandler = onSyncJobCreatedHandler; + events.on(serverNotifications, 'SyncJobCreated', onSyncJobCreatedHandler); + var onSyncJobCancelledHandler = onSyncJobCancelled.bind(this); - this.onSyncJobCancelledHandler = onSyncJobCancelledHandler, events.on(serverNotifications, "SyncJobCancelled", onSyncJobCancelledHandler); + this.onSyncJobCancelledHandler = onSyncJobCancelledHandler; + events.on(serverNotifications, 'SyncJobCancelled', onSyncJobCancelledHandler); + var onSyncJobUpdatedHandler = onSyncJobUpdated.bind(this); - this.onSyncJobUpdatedHandler = onSyncJobUpdatedHandler, events.on(serverNotifications, "SyncJobUpdated", onSyncJobUpdatedHandler); + this.onSyncJobUpdatedHandler = onSyncJobUpdatedHandler; + events.on(serverNotifications, 'SyncJobUpdated', onSyncJobUpdatedHandler); + var onClickHandler = onElementClick.bind(this); - options.element.addEventListener("click", onClickHandler), this.onClickHandler = onClickHandler, options.element.innerHTML = '
    ', fetchData(this), initSupporterInfo(options.element, getApiClient(this)) + options.element.addEventListener('click', onClickHandler); + this.onClickHandler = onClickHandler; + + options.element.innerHTML = '
    '; + + fetchData(this); + + initSupporterInfo(options.element, getApiClient(this)); } function showSupporterInfo(context) { + var html = '", html += '", html += "", html += "" + + var html = ''; + + html += '
    '; + html += '
    '; + + html += '
    '; + + html += '

     

    '; + + html += '

    '; + + html += '
    '; + html += '
    '; + + html += '
    '; + + html += '
    '; + + html += ''; + + html += ''; + + // buttons + html += '
    '; + + // main + html += '
    '; + + return html; } function setNextVideoText() { - var instance = this, - elem = instance.options.parent, - secondsRemaining = Math.max(Math.round(getTimeRemainingMs(instance) / 1e3), 0); - console.log("up next seconds remaining: " + secondsRemaining); - var timeText = '' + globalize.translate("sharedcomponents#HeaderSecondsValue", secondsRemaining) + "", - nextVideoText = "Episode" === instance.itemType ? globalize.translate("sharedcomponents#HeaderNextEpisodePlayingInValue", timeText) : globalize.translate("sharedcomponents#HeaderNextVideoPlayingInValue", timeText); - elem.querySelector(".upNextDialog-nextVideoText").innerHTML = nextVideoText + + var instance = this; + + var elem = instance.options.parent; + + var secondsRemaining = Math.max(Math.round(getTimeRemainingMs(instance) / 1000), 0); + + console.log('up next seconds remaining: ' + secondsRemaining); + + var timeText = '' + globalize.translate('sharedcomponents#HeaderSecondsValue', secondsRemaining) + ''; + + var nextVideoText = instance.itemType === 'Episode' ? + globalize.translate('sharedcomponents#HeaderNextEpisodePlayingInValue', timeText) : + globalize.translate('sharedcomponents#HeaderNextVideoPlayingInValue', timeText); + + elem.querySelector('.upNextDialog-nextVideoText').innerHTML = nextVideoText; } function fillItem(item) { - var instance = this, - elem = instance.options.parent; - setPoster(elem.querySelector(".upNextDialog-poster"), item), elem.querySelector(".upNextDialog-overview").innerHTML = item.Overview || "", elem.querySelector(".upNextDialog-mediainfo").innerHTML = mediaInfo.getPrimaryMediaInfoHtml(item, {}); + + var instance = this; + + var elem = instance.options.parent; + + setPoster(elem.querySelector('.upNextDialog-poster'), item); + + elem.querySelector('.upNextDialog-overview').innerHTML = item.Overview || ''; + + elem.querySelector('.upNextDialog-mediainfo').innerHTML = mediaInfo.getPrimaryMediaInfoHtml(item, { + }); + var title = itemHelper.getDisplayName(item); - item.SeriesName && (title = item.SeriesName + " - " + title), elem.querySelector(".upNextDialog-title").innerHTML = title || "", instance.itemType = item.Type, instance.show() + if (item.SeriesName) { + title = item.SeriesName + ' - ' + title; + } + + elem.querySelector('.upNextDialog-title').innerHTML = title || ''; + + instance.itemType = item.Type; + + instance.show(); } function clearCountdownTextTimeout(instance) { - instance._countdownTextTimeout && (clearInterval(instance._countdownTextTimeout), instance._countdownTextTimeout = null) + if (instance._countdownTextTimeout) { + clearInterval(instance._countdownTextTimeout); + instance._countdownTextTimeout = null; + } } function onStartNowClick() { + var options = this.options; + if (options) { + var player = options.player; - this.hide(), playbackManager.nextTrack(player) + + this.hide(); + + playbackManager.nextTrack(player); } } function init(instance, options) { - options.parent.innerHTML = getHtml(), options.parent.classList.add("hide"), options.parent.classList.add("upNextDialog"), options.parent.classList.add("upNextDialog-hidden"), fillItem.call(instance, options.nextItem), options.parent.querySelector(".btnHide").addEventListener("click", instance.hide.bind(instance)), options.parent.querySelector(".btnStartNow").addEventListener("click", onStartNowClick.bind(instance)) + + options.parent.innerHTML = getHtml(); + + options.parent.classList.add('hide'); + options.parent.classList.add('upNextDialog'); + options.parent.classList.add('upNextDialog-hidden'); + + fillItem.call(instance, options.nextItem); + + options.parent.querySelector('.btnHide').addEventListener('click', instance.hide.bind(instance)); + options.parent.querySelector('.btnStartNow').addEventListener('click', onStartNowClick.bind(instance)); } function clearHideAnimationEventListeners(instance, elem) { + var fn = instance._onHideAnimationComplete; - fn && dom.removeEventListener(elem, transitionEndEventName, fn, { - once: !0 - }) + + if (fn) { + dom.removeEventListener(elem, transitionEndEventName, fn, { + once: true + }); + } } function onHideAnimationComplete(e) { - var instance = this, - elem = e.target; - elem.classList.add("hide"), clearHideAnimationEventListeners(instance, elem), events.trigger(instance, "hide") + + var instance = this; + var elem = e.target; + + elem.classList.add('hide'); + + clearHideAnimationEventListeners(instance, elem); + events.trigger(instance, 'hide'); } function hideComingUpNext() { + var instance = this; - if (clearCountdownTextTimeout(this), instance.options) { - var elem = instance.options.parent; - if (elem && (clearHideAnimationEventListeners(this, elem), !elem.classList.contains("upNextDialog-hidden"))) { - elem.offsetWidth, elem.classList.add("upNextDialog-hidden"); - var fn = onHideAnimationComplete.bind(instance); - instance._onHideAnimationComplete = fn, dom.addEventListener(elem, transitionEndEventName, fn, { - once: !0 - }) - } + clearCountdownTextTimeout(this); + + if (!instance.options) { + return; } + + var elem = instance.options.parent; + + if (!elem) { + return; + } + + clearHideAnimationEventListeners(this, elem); + + if (elem.classList.contains('upNextDialog-hidden')) { + return; + } + + // trigger a reflow to force it to animate again + void elem.offsetWidth; + + elem.classList.add('upNextDialog-hidden'); + + var fn = onHideAnimationComplete.bind(instance); + instance._onHideAnimationComplete = fn; + + dom.addEventListener(elem, transitionEndEventName, fn, { + once: true + }); } function getTimeRemainingMs(instance) { + var options = instance.options; if (options) { + var runtimeTicks = playbackManager.duration(options.player); + if (runtimeTicks) { var timeRemainingTicks = runtimeTicks - playbackManager.currentTime(options.player); - return Math.round(timeRemainingTicks / 1e4) + + return Math.round(timeRemainingTicks / 10000); } } - return 0 + + return 0; } function startComingUpNextHideTimer(instance) { - getTimeRemainingMs(instance) <= 0 || (setNextVideoText.call(instance), clearCountdownTextTimeout(instance), instance._countdownTextTimeout = setInterval(setNextVideoText.bind(instance), 400)) + + var timeRemainingMs = getTimeRemainingMs(instance); + + if (timeRemainingMs <= 0) { + return; + } + + setNextVideoText.call(instance); + clearCountdownTextTimeout(instance); + + instance._countdownTextTimeout = setInterval(setNextVideoText.bind(instance), 400); } function UpNextDialog(options) { - this.options = options, init(this, options) + + this.options = options; + + init(this, options); } - var transitionEndEventName = dom.whichTransitionEvent(); - return UpNextDialog.prototype.show = function() { + + UpNextDialog.prototype.show = function () { + var elem = this.options.parent; - clearHideAnimationEventListeners(this, elem), elem.classList.remove("hide"), elem.offsetWidth, elem.classList.remove("upNextDialog-hidden"), layoutManager.tv && setTimeout(function() { - focusManager.focus(elem.querySelector(".btnStartNow")) - }, 50), startComingUpNextHideTimer(this) - }, UpNextDialog.prototype.hide = function() { - hideComingUpNext.call(this) - }, UpNextDialog.prototype.destroy = function() { - hideComingUpNext.call(this), this.options = null, this.itemType = null - }, UpNextDialog + + clearHideAnimationEventListeners(this, elem); + + elem.classList.remove('hide'); + + // trigger a reflow to force it to animate again + void elem.offsetWidth; + + elem.classList.remove('upNextDialog-hidden'); + + if (layoutManager.tv) { + setTimeout(function () { + focusManager.focus(elem.querySelector('.btnStartNow')); + }, 50); + } + + startComingUpNextHideTimer(this); + }; + + UpNextDialog.prototype.hide = function () { + + hideComingUpNext.call(this); + }; + + UpNextDialog.prototype.destroy = function () { + + hideComingUpNext.call(this); + + this.options = null; + this.itemType = null; + }; + + return UpNextDialog; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/userdatabuttons/emby-playstatebutton.js b/src/bower_components/emby-webcomponents/userdatabuttons/emby-playstatebutton.js index d0aa874321..95e9ba8f2e 100644 --- a/src/bower_components/emby-webcomponents/userdatabuttons/emby-playstatebutton.js +++ b/src/bower_components/emby-webcomponents/userdatabuttons/emby-playstatebutton.js @@ -1,64 +1,175 @@ -define(["connectionManager", "serverNotifications", "events", "globalize", "emby-button"], function(connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) { - "use strict"; +define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby-button'], function (connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) { + 'use strict'; function addNotificationEvent(instance, name, handler) { + var localHandler = handler.bind(instance); - events.on(serverNotifications, name, localHandler), instance[name] = localHandler + events.on(serverNotifications, name, localHandler); + instance[name] = localHandler; } function removeNotificationEvent(instance, name) { + var handler = instance[name]; - handler && (events.off(serverNotifications, name, handler), instance[name] = null) + if (handler) { + events.off(serverNotifications, name, handler); + instance[name] = null; + } } function onClick(e) { - var button = this, - id = button.getAttribute("data-id"), - serverId = button.getAttribute("data-serverid"), - apiClient = connectionManager.getApiClient(serverId); - button.classList.contains("playstatebutton-played") ? (apiClient.markUnplayed(apiClient.getCurrentUserId(), id, new Date), setState(button, !1)) : (apiClient.markPlayed(apiClient.getCurrentUserId(), id, new Date), setState(button, !0)) + + var button = this; + var id = button.getAttribute('data-id'); + var serverId = button.getAttribute('data-serverid'); + var apiClient = connectionManager.getApiClient(serverId); + + if (!button.classList.contains('playstatebutton-played')) { + + apiClient.markPlayed(apiClient.getCurrentUserId(), id, new Date()); + + setState(button, true); + + } else { + + apiClient.markUnplayed(apiClient.getCurrentUserId(), id, new Date()); + + setState(button, false); + } } function onUserDataChanged(e, apiClient, userData) { + var button = this; - userData.ItemId === button.getAttribute("data-id") && setState(button, userData.Played) + + if (userData.ItemId === button.getAttribute('data-id')) { + + setState(button, userData.Played); + } } function setState(button, played, updateAttribute) { + var icon = button.iconElement; - icon || (button.iconElement = button.querySelector("i"), icon = button.iconElement), played ? (button.classList.add("playstatebutton-played"), icon && (icon.classList.add("playstatebutton-icon-played"), icon.classList.remove("playstatebutton-icon-unplayed"))) : (button.classList.remove("playstatebutton-played"), icon && (icon.classList.remove("playstatebutton-icon-played"), icon.classList.add("playstatebutton-icon-unplayed"))), !1 !== updateAttribute && button.setAttribute("data-played", played) + if (!icon) { + button.iconElement = button.querySelector('i'); + icon = button.iconElement; + } + + if (played) { + + button.classList.add('playstatebutton-played'); + + if (icon) { + icon.classList.add('playstatebutton-icon-played'); + icon.classList.remove('playstatebutton-icon-unplayed'); + } + + } else { + + button.classList.remove('playstatebutton-played'); + + if (icon) { + icon.classList.remove('playstatebutton-icon-played'); + icon.classList.add('playstatebutton-icon-unplayed'); + } + } + + if (updateAttribute !== false) { + button.setAttribute('data-played', played); + } } function setTitle(button, itemType) { - button.title = "AudioBook" !== itemType && "AudioPodcast" !== itemType ? globalize.translate("sharedcomponents#Watched") : globalize.translate("sharedcomponents#Played"); - var text = button.querySelector(".button-text"); - text && (text.innerHTML = button.title) + + if (itemType !== 'AudioBook' && itemType !== 'AudioPodcast') { + button.title = globalize.translate('sharedcomponents#Watched'); + } else { + button.title = globalize.translate('sharedcomponents#Played'); + } + + var text = button.querySelector('.button-text'); + if (text) { + text.innerHTML = button.title; + } } function clearEvents(button) { - button.removeEventListener("click", onClick), removeNotificationEvent(button, "UserDataChanged") + + button.removeEventListener('click', onClick); + removeNotificationEvent(button, 'UserDataChanged'); } function bindEvents(button) { - clearEvents(button), button.addEventListener("click", onClick), addNotificationEvent(button, "UserDataChanged", onUserDataChanged) + + clearEvents(button); + + button.addEventListener('click', onClick); + addNotificationEvent(button, 'UserDataChanged', onUserDataChanged); } + var EmbyPlaystateButtonPrototype = Object.create(EmbyButtonPrototype); - EmbyPlaystateButtonPrototype.createdCallback = function() { - EmbyButtonPrototype.createdCallback && EmbyButtonPrototype.createdCallback.call(this) - }, EmbyPlaystateButtonPrototype.attachedCallback = function() { - EmbyButtonPrototype.attachedCallback && EmbyButtonPrototype.attachedCallback.call(this); - var itemId = this.getAttribute("data-id"), - serverId = this.getAttribute("data-serverid"); - itemId && serverId && (setState(this, "true" === this.getAttribute("data-played"), !1), bindEvents(this), setTitle(this, this.getAttribute("data-type"))) - }, EmbyPlaystateButtonPrototype.detachedCallback = function() { - EmbyButtonPrototype.detachedCallback && EmbyButtonPrototype.detachedCallback.call(this), clearEvents(this), this.iconElement = null - }, EmbyPlaystateButtonPrototype.setItem = function(item) { + + EmbyPlaystateButtonPrototype.createdCallback = function () { + + // base method + if (EmbyButtonPrototype.createdCallback) { + EmbyButtonPrototype.createdCallback.call(this); + } + }; + + EmbyPlaystateButtonPrototype.attachedCallback = function () { + + // base method + if (EmbyButtonPrototype.attachedCallback) { + EmbyButtonPrototype.attachedCallback.call(this); + } + + var itemId = this.getAttribute('data-id'); + var serverId = this.getAttribute('data-serverid'); + if (itemId && serverId) { + + setState(this, this.getAttribute('data-played') === 'true', false); + bindEvents(this); + setTitle(this, this.getAttribute('data-type')); + } + }; + + EmbyPlaystateButtonPrototype.detachedCallback = function () { + + // base method + if (EmbyButtonPrototype.detachedCallback) { + EmbyButtonPrototype.detachedCallback.call(this); + } + + clearEvents(this); + this.iconElement = null; + }; + + EmbyPlaystateButtonPrototype.setItem = function (item) { + if (item) { - this.setAttribute("data-id", item.Id), this.setAttribute("data-serverid", item.ServerId); - setState(this, item.UserData && item.UserData.Played), bindEvents(this), setTitle(this, item.Type) - } else this.removeAttribute("data-id"), this.removeAttribute("data-serverid"), this.removeAttribute("data-played"), clearEvents(this) - }, document.registerElement("emby-playstatebutton", { + + this.setAttribute('data-id', item.Id); + this.setAttribute('data-serverid', item.ServerId); + + var played = item.UserData && item.UserData.Played; + setState(this, played); + bindEvents(this); + + setTitle(this, item.Type); + + } else { + + this.removeAttribute('data-id'); + this.removeAttribute('data-serverid'); + this.removeAttribute('data-played'); + clearEvents(this); + } + }; + + document.registerElement('emby-playstatebutton', { prototype: EmbyPlaystateButtonPrototype, - extends: "button" - }) + extends: 'button' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/userdatabuttons/emby-ratingbutton.js b/src/bower_components/emby-webcomponents/userdatabuttons/emby-ratingbutton.js index 2363e9a34e..b50a308177 100644 --- a/src/bower_components/emby-webcomponents/userdatabuttons/emby-ratingbutton.js +++ b/src/bower_components/emby-webcomponents/userdatabuttons/emby-ratingbutton.js @@ -1,78 +1,204 @@ -define(["connectionManager", "serverNotifications", "events", "globalize", "emby-button"], function(connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) { - "use strict"; +define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby-button'], function (connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) { + 'use strict'; function addNotificationEvent(instance, name, handler) { + var localHandler = handler.bind(instance); - events.on(serverNotifications, name, localHandler), instance[name] = localHandler + events.on(serverNotifications, name, localHandler); + instance[name] = localHandler; } function removeNotificationEvent(instance, name) { + var handler = instance[name]; - handler && (events.off(serverNotifications, name, handler), instance[name] = null) + if (handler) { + events.off(serverNotifications, name, handler); + instance[name] = null; + } } function showPicker(button, apiClient, itemId, likes, isFavorite) { - return apiClient.updateFavoriteStatus(apiClient.getCurrentUserId(), itemId, !isFavorite) + + return apiClient.updateFavoriteStatus(apiClient.getCurrentUserId(), itemId, !isFavorite); } function onClick(e) { - var button = this, - id = button.getAttribute("data-id"), - serverId = button.getAttribute("data-serverid"), - apiClient = connectionManager.getApiClient(serverId), - likes = this.getAttribute("data-likes"), - isFavorite = "true" === this.getAttribute("data-isfavorite"); - likes = "true" === likes || "false" !== likes && null, showPicker(button, apiClient, id, likes, isFavorite).then(function(userData) { - setState(button, userData.Likes, userData.IsFavorite) - }) + + var button = this; + var id = button.getAttribute('data-id'); + var serverId = button.getAttribute('data-serverid'); + var apiClient = connectionManager.getApiClient(serverId); + + var likes = this.getAttribute('data-likes'); + var isFavorite = this.getAttribute('data-isfavorite') === 'true'; + if (likes === 'true') { + likes = true; + } + else if (likes === 'false') { + likes = false; + } else { + likes = null; + } + + showPicker(button, apiClient, id, likes, isFavorite).then(function (userData) { + + setState(button, userData.Likes, userData.IsFavorite); + }); } function onUserDataChanged(e, apiClient, userData) { + var button = this; - userData.ItemId === button.getAttribute("data-id") && setState(button, userData.Likes, userData.IsFavorite) + + if (userData.ItemId === button.getAttribute('data-id')) { + + setState(button, userData.Likes, userData.IsFavorite); + } } function setState(button, likes, isFavorite, updateAttribute) { - var icon = button.querySelector("i"); - isFavorite ? (icon && (icon.innerHTML = "", icon.classList.add("ratingbutton-icon-withrating")), button.classList.add("ratingbutton-withrating")) : (icon && (icon.innerHTML = "", icon.classList.remove("ratingbutton-icon-withrating")), button.classList.remove("ratingbutton-withrating")), !1 !== updateAttribute && (button.setAttribute("data-isfavorite", isFavorite), button.setAttribute("data-likes", null === likes ? "" : likes)) + + var icon = button.querySelector('i'); + + if (isFavorite) { + + if (icon) { + icon.innerHTML = ''; + icon.classList.add('ratingbutton-icon-withrating'); + } + + button.classList.add('ratingbutton-withrating'); + + } else if (likes) { + + if (icon) { + icon.innerHTML = ''; + icon.classList.remove('ratingbutton-icon-withrating'); + //icon.innerHTML = ''; + } + button.classList.remove('ratingbutton-withrating'); + + } else if (likes === false) { + + if (icon) { + icon.innerHTML = ''; + icon.classList.remove('ratingbutton-icon-withrating'); + //icon.innerHTML = ''; + } + button.classList.remove('ratingbutton-withrating'); + + } else { + + if (icon) { + icon.innerHTML = ''; + icon.classList.remove('ratingbutton-icon-withrating'); + //icon.innerHTML = ''; + } + button.classList.remove('ratingbutton-withrating'); + } + + if (updateAttribute !== false) { + button.setAttribute('data-isfavorite', isFavorite); + + button.setAttribute('data-likes', (likes === null ? '' : likes)); + } } function setTitle(button) { - button.title = globalize.translate("sharedcomponents#Favorite"); - var text = button.querySelector(".button-text"); - text && (text.innerHTML = button.title) + button.title = globalize.translate('sharedcomponents#Favorite'); + + var text = button.querySelector('.button-text'); + if (text) { + text.innerHTML = button.title; + } } function clearEvents(button) { - button.removeEventListener("click", onClick), removeNotificationEvent(button, "UserDataChanged") + + button.removeEventListener('click', onClick); + removeNotificationEvent(button, 'UserDataChanged'); } function bindEvents(button) { - clearEvents(button), button.addEventListener("click", onClick), addNotificationEvent(button, "UserDataChanged", onUserDataChanged) + + clearEvents(button); + + button.addEventListener('click', onClick); + addNotificationEvent(button, 'UserDataChanged', onUserDataChanged); } + var EmbyRatingButtonPrototype = Object.create(EmbyButtonPrototype); - EmbyRatingButtonPrototype.createdCallback = function() { - EmbyButtonPrototype.createdCallback && EmbyButtonPrototype.createdCallback.call(this) - }, EmbyRatingButtonPrototype.attachedCallback = function() { - EmbyButtonPrototype.attachedCallback && EmbyButtonPrototype.attachedCallback.call(this); - var itemId = this.getAttribute("data-id"), - serverId = this.getAttribute("data-serverid"); - if (itemId && serverId) { - var likes = this.getAttribute("data-likes"), - isFavorite = "true" === this.getAttribute("data-isfavorite"); - likes = "true" === likes || "false" !== likes && null, setState(this, likes, isFavorite, !1), bindEvents(this) + + EmbyRatingButtonPrototype.createdCallback = function () { + + // base method + if (EmbyButtonPrototype.createdCallback) { + EmbyButtonPrototype.createdCallback.call(this); } - setTitle(this) - }, EmbyRatingButtonPrototype.detachedCallback = function() { - EmbyButtonPrototype.detachedCallback && EmbyButtonPrototype.detachedCallback.call(this), clearEvents(this) - }, EmbyRatingButtonPrototype.setItem = function(item) { + }; + + EmbyRatingButtonPrototype.attachedCallback = function () { + + // base method + if (EmbyButtonPrototype.attachedCallback) { + EmbyButtonPrototype.attachedCallback.call(this); + } + + var itemId = this.getAttribute('data-id'); + var serverId = this.getAttribute('data-serverid'); + if (itemId && serverId) { + + var likes = this.getAttribute('data-likes'); + var isFavorite = this.getAttribute('data-isfavorite') === 'true'; + if (likes === 'true') { + likes = true; + } + else if (likes === 'false') { + likes = false; + } else { + likes = null; + } + + setState(this, likes, isFavorite, false); + bindEvents(this); + } + + setTitle(this); + }; + + EmbyRatingButtonPrototype.detachedCallback = function () { + + // base method + if (EmbyButtonPrototype.detachedCallback) { + EmbyButtonPrototype.detachedCallback.call(this); + } + + clearEvents(this); + }; + + EmbyRatingButtonPrototype.setItem = function (item) { + if (item) { - this.setAttribute("data-id", item.Id), this.setAttribute("data-serverid", item.ServerId); + + this.setAttribute('data-id', item.Id); + this.setAttribute('data-serverid', item.ServerId); + var userData = item.UserData || {}; - setState(this, userData.Likes, userData.IsFavorite), bindEvents(this) - } else this.removeAttribute("data-id"), this.removeAttribute("data-serverid"), this.removeAttribute("data-likes"), this.removeAttribute("data-isfavorite"), clearEvents(this) - }, document.registerElement("emby-ratingbutton", { + setState(this, userData.Likes, userData.IsFavorite); + bindEvents(this); + + } else { + + this.removeAttribute('data-id'); + this.removeAttribute('data-serverid'); + this.removeAttribute('data-likes'); + this.removeAttribute('data-isfavorite'); + clearEvents(this); + } + }; + + document.registerElement('emby-ratingbutton', { prototype: EmbyRatingButtonPrototype, - extends: "button" - }) + extends: 'button' + }); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.css b/src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.css index 253504a2b1..0138631734 100644 --- a/src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.css +++ b/src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.css @@ -1,3 +1,3 @@ .btnUserDataOn { - color: #c33 !important + color: #cc3333 !important; } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.js b/src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.js index b1b5631468..7c3fc654f7 100644 --- a/src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.js +++ b/src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.js @@ -1,110 +1,251 @@ -define(["connectionManager", "globalize", "dom", "itemHelper", "paper-icon-button-light", "material-icons", "emby-button", "css!./userdatabuttons"], function(connectionManager, globalize, dom, itemHelper) { - "use strict"; +define(['connectionManager', 'globalize', 'dom', 'itemHelper', 'paper-icon-button-light', 'material-icons', 'emby-button', 'css!./userdatabuttons'], function (connectionManager, globalize, dom, itemHelper) { + 'use strict'; - function getUserDataButtonHtml(method, itemId, serverId, buttonCssClass, iconCssClass, icon, tooltip, style) { - "fab-mini" === style && (style = "fab", buttonCssClass = buttonCssClass ? buttonCssClass + " mini" : "mini"); - var is = "fab" === style ? "emby-button" : "paper-icon-button-light", - className = "fab" === style ? "autoSize fab" : "autoSize"; - return buttonCssClass && (className += " " + buttonCssClass), iconCssClass ? iconCssClass += " " : iconCssClass = "", iconCssClass += "md-icon", '" - } - - function onContainerClick(e) { - var btnUserData = dom.parentWithClass(e.target, "btnUserData"); - if (btnUserData) { - var method = btnUserData.getAttribute("data-method"); - userDataMethods[method](btnUserData) - } - } - - function fill(options) { - var html = getIconsHtml(options); - "insertAdjacent" === options.fillMode ? options.element.insertAdjacentHTML(options.insertLocation || "beforeend", html) : options.element.innerHTML = html, dom.removeEventListener(options.element, "click", onContainerClick, { - passive: !0 - }), dom.addEventListener(options.element, "click", onContainerClick, { - passive: !0 - }) - } - - function destroy(options) { - options.element.innerHTML = "", dom.removeEventListener(options.element, "click", onContainerClick, { - passive: !0 - }) - } - - function getIconsHtml(options) { - var item = options.item, - includePlayed = options.includePlayed, - cssClass = options.cssClass, - style = options.style, - html = "", - userData = item.UserData || {}, - itemId = item.Id; - if (itemHelper.isLocalItem(item)) return html; - var btnCssClass = "btnUserData"; - cssClass && (btnCssClass += " " + cssClass); - var iconCssClass = options.iconCssClass, - serverId = item.ServerId; - if (!1 !== includePlayed) { - var tooltipPlayed = globalize.translate("sharedcomponents#MarkPlayed"); - itemHelper.canMarkPlayed(item) && (html += userData.Played ? getUserDataButtonHtml("markPlayed", itemId, serverId, btnCssClass + " btnUserDataOn", iconCssClass, "", tooltipPlayed, style) : getUserDataButtonHtml("markPlayed", itemId, serverId, btnCssClass, iconCssClass, "", tooltipPlayed, style)) - } - var tooltipFavorite = globalize.translate("sharedcomponents#Favorite"); - return html += userData.IsFavorite ? getUserDataButtonHtml("markFavorite", itemId, serverId, btnCssClass + " btnUserData btnUserDataOn", iconCssClass, "", tooltipFavorite, style) : getUserDataButtonHtml("markFavorite", itemId, serverId, btnCssClass + " btnUserData", iconCssClass, "", tooltipFavorite, style) - } - - function markFavorite(link) { - var id = link.getAttribute("data-itemid"), - serverId = link.getAttribute("data-serverid"), - markAsFavorite = !link.classList.contains("btnUserDataOn"); - favorite(id, serverId, markAsFavorite), markAsFavorite ? link.classList.add("btnUserDataOn") : link.classList.remove("btnUserDataOn") - } - - function markLike(link) { - var id = link.getAttribute("data-itemid"), - serverId = link.getAttribute("data-serverid"); - link.classList.contains("btnUserDataOn") ? (clearLike(id, serverId), link.classList.remove("btnUserDataOn")) : (likes(id, serverId, !0), link.classList.add("btnUserDataOn")), link.parentNode.querySelector(".btnDislike").classList.remove("btnUserDataOn") - } - - function markDislike(link) { - var id = link.getAttribute("data-itemid"), - serverId = link.getAttribute("data-serverid"); - link.classList.contains("btnUserDataOn") ? (clearLike(id, serverId), link.classList.remove("btnUserDataOn")) : (likes(id, serverId, !1), link.classList.add("btnUserDataOn")), link.parentNode.querySelector(".btnLike").classList.remove("btnUserDataOn") - } - - function markPlayed(link) { - var id = link.getAttribute("data-itemid"), - serverId = link.getAttribute("data-serverid"); - link.classList.contains("btnUserDataOn") ? (played(id, serverId, !1), link.classList.remove("btnUserDataOn")) : (played(id, serverId, !0), link.classList.add("btnUserDataOn")) - } - - function likes(id, serverId, isLiked) { - var apiClient = connectionManager.getApiClient(serverId); - return apiClient.updateUserItemRating(apiClient.getCurrentUserId(), id, isLiked) - } - - function played(id, serverId, isPlayed) { - var apiClient = connectionManager.getApiClient(serverId); - return apiClient[isPlayed ? "markPlayed" : "markUnplayed"](apiClient.getCurrentUserId(), id, new Date) - } - - function favorite(id, serverId, isFavorite) { - var apiClient = connectionManager.getApiClient(serverId); - return apiClient.updateFavoriteStatus(apiClient.getCurrentUserId(), id, isFavorite) - } - - function clearLike(id, serverId) { - var apiClient = connectionManager.getApiClient(serverId); - return apiClient.clearUserItemRating(apiClient.getCurrentUserId(), id) - } var userDataMethods = { markPlayed: markPlayed, markDislike: markDislike, markLike: markLike, markFavorite: markFavorite }; + + function getUserDataButtonHtml(method, itemId, serverId, buttonCssClass, iconCssClass, icon, tooltip, style) { + + if (style === 'fab-mini') { + style = 'fab'; + buttonCssClass = buttonCssClass ? (buttonCssClass + ' mini') : 'mini'; + } + + var is = style === 'fab' ? 'emby-button' : 'paper-icon-button-light'; + var className = style === 'fab' ? 'autoSize fab' : 'autoSize'; + + if (buttonCssClass) { + className += ' ' + buttonCssClass; + } + + if (iconCssClass) { + iconCssClass += ' '; + } else { + iconCssClass = ''; + } + + iconCssClass += 'md-icon'; + + return ''; + } + + function onContainerClick(e) { + + var btnUserData = dom.parentWithClass(e.target, 'btnUserData'); + + if (!btnUserData) { + return; + } + + var method = btnUserData.getAttribute('data-method'); + userDataMethods[method](btnUserData); + } + + function fill(options) { + + var html = getIconsHtml(options); + + if (options.fillMode === 'insertAdjacent') { + options.element.insertAdjacentHTML(options.insertLocation || 'beforeend', html); + } else { + options.element.innerHTML = html; + } + + dom.removeEventListener(options.element, 'click', onContainerClick, { + passive: true + }); + + dom.addEventListener(options.element, 'click', onContainerClick, { + passive: true + }); + } + + function destroy(options) { + + options.element.innerHTML = ''; + + dom.removeEventListener(options.element, 'click', onContainerClick, { + passive: true + }); + } + + function getIconsHtml(options) { + + var item = options.item; + var includePlayed = options.includePlayed; + var cssClass = options.cssClass; + var style = options.style; + + var html = ''; + + var userData = item.UserData || {}; + + var itemId = item.Id; + + if (itemHelper.isLocalItem(item)) { + return html; + } + + var btnCssClass = "btnUserData"; + + if (cssClass) { + btnCssClass += " " + cssClass; + } + + var iconCssClass = options.iconCssClass; + + var serverId = item.ServerId; + + if (includePlayed !== false) { + var tooltipPlayed = globalize.translate('sharedcomponents#MarkPlayed'); + + if (itemHelper.canMarkPlayed(item)) { + if (userData.Played) { + html += getUserDataButtonHtml('markPlayed', itemId, serverId, btnCssClass + ' btnUserDataOn', iconCssClass, '', tooltipPlayed, style); + } else { + html += getUserDataButtonHtml('markPlayed', itemId, serverId, btnCssClass, iconCssClass, '', tooltipPlayed, style); + } + } + } + + //var tooltipLike = globalize.translate('sharedcomponents#Like'); + //var tooltipDislike = globalize.translate('sharedcomponents#Dislike'); + + //if (typeof userData.Likes == "undefined") { + // html += getUserDataButtonHtml('markDislike', itemId, serverId, btnCssClass + ' btnUserData btnDislike', 'thumb-down', tooltipDislike); + // html += getUserDataButtonHtml('markLike', itemId, serverId, btnCssClass + ' btnUserData btnLike', 'thumb-up', tooltipLike); + //} + //else if (userData.Likes) { + // html += getUserDataButtonHtml('markDislike', itemId, serverId, btnCssClass + ' btnUserData btnDislike', 'thumb-down', tooltipDislike); + // html += getUserDataButtonHtml('markLike', itemId, serverId, btnCssClass + ' btnUserData btnLike btnUserDataOn', 'thumb-up', tooltipLike); + //} + //else { + // html += getUserDataButtonHtml('markDislike', itemId, serverId, btnCssClass + ' btnUserData btnDislike btnUserDataOn', 'thumb-down', tooltipDislike); + // html += getUserDataButtonHtml('markLike', itemId, serverId, btnCssClass + ' btnUserData btnLike', 'thumb-up', tooltipLike); + //} + + var tooltipFavorite = globalize.translate('sharedcomponents#Favorite'); + if (userData.IsFavorite) { + + html += getUserDataButtonHtml('markFavorite', itemId, serverId, btnCssClass + ' btnUserData btnUserDataOn', iconCssClass, '', tooltipFavorite, style); + } else { + html += getUserDataButtonHtml('markFavorite', itemId, serverId, btnCssClass + ' btnUserData', iconCssClass, '', tooltipFavorite, style); + } + + return html; + } + + function markFavorite(link) { + + var id = link.getAttribute('data-itemid'); + var serverId = link.getAttribute('data-serverid'); + + var markAsFavorite = !link.classList.contains('btnUserDataOn'); + + favorite(id, serverId, markAsFavorite); + + if (markAsFavorite) { + link.classList.add('btnUserDataOn'); + } else { + link.classList.remove('btnUserDataOn'); + } + } + + function markLike(link) { + + var id = link.getAttribute('data-itemid'); + var serverId = link.getAttribute('data-serverid'); + + if (!link.classList.contains('btnUserDataOn')) { + + likes(id, serverId, true); + + link.classList.add('btnUserDataOn'); + + } else { + + clearLike(id, serverId); + + link.classList.remove('btnUserDataOn'); + } + + link.parentNode.querySelector('.btnDislike').classList.remove('btnUserDataOn'); + } + + function markDislike(link) { + + var id = link.getAttribute('data-itemid'); + var serverId = link.getAttribute('data-serverid'); + + if (!link.classList.contains('btnUserDataOn')) { + + likes(id, serverId, false); + + link.classList.add('btnUserDataOn'); + + } else { + + clearLike(id, serverId); + + link.classList.remove('btnUserDataOn'); + } + + link.parentNode.querySelector('.btnLike').classList.remove('btnUserDataOn'); + } + + function markPlayed(link) { + + var id = link.getAttribute('data-itemid'); + var serverId = link.getAttribute('data-serverid'); + + if (!link.classList.contains('btnUserDataOn')) { + + played(id, serverId, true); + + link.classList.add('btnUserDataOn'); + + } else { + + played(id, serverId, false); + + link.classList.remove('btnUserDataOn'); + } + } + + function likes(id, serverId, isLiked) { + var apiClient = connectionManager.getApiClient(serverId); + return apiClient.updateUserItemRating(apiClient.getCurrentUserId(), id, isLiked); + } + + function played(id, serverId, isPlayed) { + var apiClient = connectionManager.getApiClient(serverId); + + var method = isPlayed ? 'markPlayed' : 'markUnplayed'; + + return apiClient[method](apiClient.getCurrentUserId(), id, new Date()); + } + + function favorite(id, serverId, isFavorite) { + var apiClient = connectionManager.getApiClient(serverId); + + return apiClient.updateFavoriteStatus(apiClient.getCurrentUserId(), id, isFavorite); + } + + function clearLike(id, serverId) { + + var apiClient = connectionManager.getApiClient(serverId); + + return apiClient.clearUserItemRating(apiClient.getCurrentUserId(), id); + } + return { fill: fill, destroy: destroy, getIconsHtml: getIconsHtml - } + }; + }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/usersettings/usersettings.js b/src/bower_components/emby-webcomponents/usersettings/usersettings.js index 0712e46299..6b3dc90d49 100644 --- a/src/bower_components/emby-webcomponents/usersettings/usersettings.js +++ b/src/bower_components/emby-webcomponents/usersettings/usersettings.js @@ -1,4 +1,5 @@ -define(["userSettingsBuilder"], function(userSettingsBuilder) { - "use strict"; - return new userSettingsBuilder +define(['userSettingsBuilder'], function (userSettingsBuilder) { + 'use strict'; + + return new userSettingsBuilder(); }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/usersettings/usersettingsbuilder.js b/src/bower_components/emby-webcomponents/usersettings/usersettingsbuilder.js index 568b1fcaa6..6d0bc58d06 100644 --- a/src/bower_components/emby-webcomponents/usersettings/usersettingsbuilder.js +++ b/src/bower_components/emby-webcomponents/usersettings/usersettingsbuilder.js @@ -1,86 +1,324 @@ -define(["appSettings", "events"], function(appsettings, events) { - "use strict"; +define(['appSettings', 'events'], function (appsettings, events) { + 'use strict'; function onSaveTimeout() { + var self = this; - self.saveTimeout = null, self.currentApiClient.updateDisplayPreferences("usersettings", self.displayPrefs, self.currentUserId, "emby") + self.saveTimeout = null; + self.currentApiClient.updateDisplayPreferences('usersettings', self.displayPrefs, self.currentUserId, 'emby'); } function saveServerPreferences(instance) { - instance.saveTimeout && clearTimeout(instance.saveTimeout), instance.saveTimeout = setTimeout(onSaveTimeout.bind(instance), 50) + if (instance.saveTimeout) { + clearTimeout(instance.saveTimeout); + } + instance.saveTimeout = setTimeout(onSaveTimeout.bind(instance), 50); } - function UserSettings() {} - return UserSettings.prototype.setUserInfo = function(userId, apiClient) { - if (this.saveTimeout && clearTimeout(this.saveTimeout), this.currentUserId = userId, this.currentApiClient = apiClient, !userId) return this.displayPrefs = null, Promise.resolve(); + function UserSettings() { + } + + UserSettings.prototype.setUserInfo = function (userId, apiClient) { + + if (this.saveTimeout) { + clearTimeout(this.saveTimeout); + } + + this.currentUserId = userId; + this.currentApiClient = apiClient; + + if (!userId) { + this.displayPrefs = null; + return Promise.resolve(); + } + var self = this; - return apiClient.getDisplayPreferences("usersettings", userId, "emby").then(function(result) { - result.CustomPrefs = result.CustomPrefs || {}, self.displayPrefs = result - }) - }, UserSettings.prototype.getData = function() { - return this.displayPrefs - }, UserSettings.prototype.importFrom = function(instance) { - this.displayPrefs = instance.getData() - }, UserSettings.prototype.set = function(name, value, enableOnServer) { + + return apiClient.getDisplayPreferences('usersettings', userId, 'emby').then(function (result) { + result.CustomPrefs = result.CustomPrefs || {}; + self.displayPrefs = result; + }); + }; + + UserSettings.prototype.getData = function () { + return this.displayPrefs; + }; + + UserSettings.prototype.importFrom = function (instance) { + this.displayPrefs = instance.getData(); + }; + + UserSettings.prototype.set = function (name, value, enableOnServer) { + var userId = this.currentUserId; - if (!userId) throw new Error("userId cannot be null"); - var currentValue = this.get(name, enableOnServer), - result = appsettings.set(name, value, userId); - return !1 !== enableOnServer && this.displayPrefs && (this.displayPrefs.CustomPrefs[name] = null == value ? value : value.toString(), saveServerPreferences(this)), currentValue !== value && events.trigger(this, "change", [name]), result - }, UserSettings.prototype.get = function(name, enableOnServer) { + if (!userId) { + throw new Error('userId cannot be null'); + } + + var currentValue = this.get(name, enableOnServer); + var result = appsettings.set(name, value, userId); + + if (enableOnServer !== false && this.displayPrefs) { + this.displayPrefs.CustomPrefs[name] = value == null ? value : value.toString(); + saveServerPreferences(this); + } + + if (currentValue !== value) { + events.trigger(this, 'change', [name]); + } + + return result; + }; + + UserSettings.prototype.get = function (name, enableOnServer) { var userId = this.currentUserId; - return userId ? !1 !== enableOnServer && this.displayPrefs ? this.displayPrefs.CustomPrefs[name] : appsettings.get(name, userId) : null - }, UserSettings.prototype.serverConfig = function(config) { + if (!userId) { + // TODO: I'd like to continue to throw this exception but it causes issues with offline use + // Revisit in the future and restore it + return null; + //throw new Error('userId cannot be null'); + } + + if (enableOnServer !== false) { + if (this.displayPrefs) { + return this.displayPrefs.CustomPrefs[name]; + } + } + + return appsettings.get(name, userId); + }; + + UserSettings.prototype.serverConfig = function (config) { + var apiClient = this.currentApiClient; - return config ? apiClient.updateUserConfiguration(this.currentUserId, config) : apiClient.getUser(this.currentUserId).then(function(user) { - return user.Configuration - }) - }, UserSettings.prototype.enableCinemaMode = function(val) { - return null != val ? this.set("enableCinemaMode", val.toString(), !1) : !(val = this.get("enableCinemaMode", !1)) || "false" !== val - }, UserSettings.prototype.enableNextVideoInfoOverlay = function(val) { - return null != val ? this.set("enableNextVideoInfoOverlay", val.toString()) : "false" !== (val = this.get("enableNextVideoInfoOverlay")) - }, UserSettings.prototype.enableThemeSongs = function(val) { - return null != val ? this.set("enableThemeSongs", val.toString(), !1) : "false" !== (val = this.get("enableThemeSongs", !1)) - }, UserSettings.prototype.enableThemeVideos = function(val) { - return null != val ? this.set("enableThemeVideos", val.toString(), !1) : (val = this.get("enableThemeVideos", !1), val ? "false" !== val : UserSettings.defaults.enableThemeVideos) - }, UserSettings.prototype.enableBackdrops = function(val) { - return null != val ? this.set("enableBackdrops", val.toString(), !1) : (val = this.get("enableBackdrops", !1), val ? "false" !== val : UserSettings.defaults.enableBackdrops) - }, UserSettings.prototype.language = function(val) { - return null != val ? this.set("language", val.toString(), !1) : this.get("language", !1) - }, UserSettings.prototype.dateTimeLocale = function(val) { - return null != val ? this.set("datetimelocale", val.toString(), !1) : this.get("datetimelocale", !1) - }, UserSettings.prototype.skipBackLength = function(val) { - return null != val ? this.set("skipBackLength", val.toString()) : parseInt(this.get("skipBackLength") || "10000") - }, UserSettings.prototype.skipForwardLength = function(val) { - return null != val ? this.set("skipForwardLength", val.toString()) : parseInt(this.get("skipForwardLength") || "30000") - }, UserSettings.prototype.dashboardTheme = function(val) { - return null != val ? this.set("dashboardTheme", val) : this.get("dashboardTheme") - }, UserSettings.prototype.skin = function(val) { - return null != val ? this.set("skin", val, !1) : this.get("skin", !1) || UserSettings.defaults.skin - }, UserSettings.prototype.theme = function(val) { - return null != val ? this.set("appTheme", val, !1) : this.get("appTheme", !1) || UserSettings.defaults.theme - }, UserSettings.prototype.enableSeasonalThemes = function(val) { - return null != val ? this.set("enableSeasonalThemes", val, !1) : "false" !== this.get("enableSeasonalThemes", !1) - }, UserSettings.prototype.screensaver = function(val) { - return null != val ? this.set("screensaver", val, !1) : this.get("screensaver", !1) || UserSettings.defaults.screensaver - }, UserSettings.prototype.soundEffects = function(val) { - return null != val ? this.set("soundeffects", val, !1) : this.get("soundeffects", !1) || UserSettings.defaults.soundEffects - }, UserSettings.defaults = { + + if (config) { + + return apiClient.updateUserConfiguration(this.currentUserId, config); + + } else { + + return apiClient.getUser(this.currentUserId).then(function (user) { + + return user.Configuration; + }); + } + }; + + UserSettings.prototype.enableCinemaMode = function (val) { + + if (val != null) { + return this.set('enableCinemaMode', val.toString(), false); + } + + val = this.get('enableCinemaMode', false); + + if (val) { + return val !== 'false'; + } + + return true; + }; + + UserSettings.prototype.enableNextVideoInfoOverlay = function (val) { + + if (val != null) { + return this.set('enableNextVideoInfoOverlay', val.toString()); + } + + val = this.get('enableNextVideoInfoOverlay'); + + return val !== 'false'; + }; + + UserSettings.prototype.enableThemeSongs = function (val) { + + if (val != null) { + return this.set('enableThemeSongs', val.toString(), false); + } + + val = this.get('enableThemeSongs', false); + + return val !== 'false'; + }; + + UserSettings.prototype.enableThemeVideos = function (val) { + + if (val != null) { + return this.set('enableThemeVideos', val.toString(), false); + } + + val = this.get('enableThemeVideos', false); + + if (val) { + return val !== 'false'; + } + + return UserSettings.defaults.enableThemeVideos; + }; + + UserSettings.prototype.enableBackdrops = function (val) { + + if (val != null) { + return this.set('enableBackdrops', val.toString(), false); + } + + val = this.get('enableBackdrops', false); + + if (val) { + return val !== 'false'; + } + + return UserSettings.defaults.enableBackdrops; + }; + + UserSettings.prototype.language = function (val) { + + if (val != null) { + return this.set('language', val.toString(), false); + } + + return this.get('language', false); + }; + + UserSettings.prototype.dateTimeLocale = function (val) { + + if (val != null) { + return this.set('datetimelocale', val.toString(), false); + } + + return this.get('datetimelocale', false); + }; + + UserSettings.prototype.skipBackLength = function (val) { + + if (val != null) { + return this.set('skipBackLength', val.toString()); + } + + return parseInt(this.get('skipBackLength') || '10000'); + }; + + UserSettings.prototype.skipForwardLength = function (val) { + + if (val != null) { + return this.set('skipForwardLength', val.toString()); + } + + return parseInt(this.get('skipForwardLength') || '30000'); + }; + + UserSettings.prototype.dashboardTheme = function (val) { + + if (val != null) { + return this.set('dashboardTheme', val); + } + + return this.get('dashboardTheme'); + }; + + UserSettings.prototype.skin = function (val) { + + if (val != null) { + return this.set('skin', val, false); + } + + return this.get('skin', false) || UserSettings.defaults.skin; + }; + + UserSettings.prototype.theme = function (val) { + + if (val != null) { + return this.set('appTheme', val, false); + } + + return this.get('appTheme', false) || UserSettings.defaults.theme; + }; + + UserSettings.prototype.enableSeasonalThemes = function (val) { + + if (val != null) { + return this.set('enableSeasonalThemes', val, false); + } + + return this.get('enableSeasonalThemes', false) !== 'false'; + }; + + UserSettings.prototype.screensaver = function (val) { + + if (val != null) { + return this.set('screensaver', val, false); + } + + return this.get('screensaver', false) || UserSettings.defaults.screensaver; + }; + + UserSettings.prototype.soundEffects = function (val) { + + if (val != null) { + return this.set('soundeffects', val, false); + } + + return this.get('soundeffects', false) || UserSettings.defaults.soundEffects; + }; + + // apps should set these values + UserSettings.defaults = { theme: null, - enableThemeVideos: !0 - }, UserSettings.prototype.loadQuerySettings = function(key, query) { + enableThemeVideos: true + }; + + UserSettings.prototype.loadQuerySettings = function (key, query) { + var values = this.get(key); - return values ? (values = JSON.parse(values), Object.assign(query, values)) : query - }, UserSettings.prototype.saveQuerySettings = function(key, query) { + + if (values) { + + values = JSON.parse(values); + + return Object.assign(query, values); + } + + return query; + }; + + UserSettings.prototype.saveQuerySettings = function (key, query) { + var values = {}; - return query.SortBy && (values.SortBy = query.SortBy), query.SortOrder && (values.SortOrder = query.SortOrder), this.set(key, JSON.stringify(values)) - }, UserSettings.prototype.getSubtitleAppearanceSettings = function(key) { - return key = key || "localplayersubtitleappearance3", JSON.parse(this.get(key, !1) || "{}") - }, UserSettings.prototype.setSubtitleAppearanceSettings = function(value, key) { - return key = key || "localplayersubtitleappearance3", this.set(key, JSON.stringify(value), !1) - }, UserSettings.prototype.setFilter = function(key, value) { - return this.set(key, value, !0) - }, UserSettings.prototype.getFilter = function(key) { - return this.get(key, !0) - }, UserSettings + + if (query.SortBy) { + values.SortBy = query.SortBy; + } + if (query.SortOrder) { + values.SortOrder = query.SortOrder; + } + + return this.set(key, JSON.stringify(values)); + }; + + UserSettings.prototype.getSubtitleAppearanceSettings = function (key) { + + key = key || 'localplayersubtitleappearance3'; + + return JSON.parse(this.get(key, false) || '{}'); + }; + + UserSettings.prototype.setSubtitleAppearanceSettings = function (value, key) { + + key = key || 'localplayersubtitleappearance3'; + + return this.set(key, JSON.stringify(value), false); + }; + + UserSettings.prototype.setFilter = function (key, value) { + + return this.set(key, value, true); + }; + + UserSettings.prototype.getFilter = function (key) { + + return this.get(key, true); + }; + + return UserSettings; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.css b/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.css index c8c4b28a10..edfa101976 100644 --- a/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.css +++ b/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.css @@ -4,141 +4,66 @@ left: 0; right: 0; bottom: 0; - contain: layout style size -} - -@-webkit-keyframes view-fadeout { - from { - opacity: 1 - } - - to { - opacity: 0 - } + contain: layout style size; + /* Can't use will-change because it causes the alpha picker to move when the page scrolls*/ + /*will-change: transform;*/ } @keyframes view-fadeout { from { - opacity: 1 + opacity: 1; } to { - opacity: 0 + opacity: 0; } } - -@-webkit-keyframes view-fadein { - from { - opacity: 0 - } - - to { - opacity: 1 - } -} - @keyframes view-fadein { from { - opacity: 0 + opacity: 0; } to { - opacity: 1 - } -} - -@-webkit-keyframes view-slideleft { - from { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0) - } - - to { - -webkit-transform: none; - transform: none + opacity: 1; } } @keyframes view-slideleft { from { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0) + transform: translate3d(100%, 0, 0); } to { - -webkit-transform: none; - transform: none - } -} - -@-webkit-keyframes view-slideleft-r { - from { - -webkit-transform: none; - transform: none - } - - to { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0) + transform: none; } } @keyframes view-slideleft-r { from { - -webkit-transform: none; - transform: none + transform: none; } to { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0) - } -} - -@-webkit-keyframes view-slideright { - from { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0) - } - - to { - -webkit-transform: none; - transform: none + transform: translate3d(-100%, 0, 0); } } @keyframes view-slideright { from { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0) + transform: translate3d(-100%, 0, 0); } to { - -webkit-transform: none; - transform: none - } -} - -@-webkit-keyframes view-slideright-r { - from { - -webkit-transform: none; - transform: none - } - - to { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0) + transform: none; } } @keyframes view-slideright-r { from { - -webkit-transform: none; - transform: none + transform: none; } to { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0) + transform: translate3d(100%, 0, 0); } } \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.js b/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.js index 0e3f492d15..57c8fe926c 100644 --- a/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.js +++ b/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.js @@ -1,148 +1,313 @@ -define(["browser", "dom", "layoutManager", "css!./viewcontainer-lite"], function(browser, dom, layoutManager) { - "use strict"; +define(['browser', 'dom', 'layoutManager', 'css!./viewcontainer-lite'], function (browser, dom, layoutManager) { + 'use strict'; + + var mainAnimatedPages = document.querySelector('.mainAnimatedPages'); + var allPages = []; + var currentUrls = []; + var pageContainerCount = 3; + var selectedPageIndex = -1; function enableAnimation() { - return !browser.tv && browser.supportsCssAnimation() + + // too slow + if (browser.tv) { + return false; + } + + return browser.supportsCssAnimation(); } function findLastView(parent, className) { - for (var nodes = parent.childNodes, i = nodes.length - 1; i >= 0; i--) { - var node = nodes[i], - classList = node.classList; - if (classList && classList.contains(className)) return node + + var nodes = parent.childNodes; + for (var i = nodes.length - 1; i >= 0; i--) { + var node = nodes[i]; + var classList = node.classList; + if (classList && classList.contains(className)) { + return node; + } } } function findViewBefore(elem, className) { - for (var node = elem.previousSibling; node;) { + + var node = elem.previousSibling; + while (node) { var classList = node.classList; - if (classList && classList.contains(className)) return node; - node = node.previousSibling + if (classList && classList.contains(className)) { + return node; + } + + node = node.previousSibling; } } function loadView(options) { - if (!options.cancel) { - cancelActiveAnimations(); - var selected = selectedPageIndex, - previousAnimatable = -1 === selected ? null : allPages[selected], - pageIndex = selected + 1; - pageIndex >= pageContainerCount && (pageIndex = 0); - var viewHtml = options.view, - properties = []; - options.fullscreen && properties.push("fullscreen"); - var view, currentPage = allPages[pageIndex]; - return currentPage ? (triggerDestroy(currentPage), currentPage.insertAdjacentHTML("beforebegin", viewHtml), view = findViewBefore(currentPage, "view"), mainAnimatedPages.removeChild(currentPage)) : (mainAnimatedPages.insertAdjacentHTML("beforeend", viewHtml), view = findLastView(mainAnimatedPages, "view")), view.classList.add("mainAnimatedPage"), properties.length && view.setAttribute("data-properties", properties.join(",")), options.type && view.setAttribute("data-type", options.type), allPages[pageIndex] = view, onBeforeChange && onBeforeChange(view, !1, options), beforeAnimate(allPages, pageIndex, selected), animate(view, previousAnimatable, options.transition, options.isBack).then(function() { - return selectedPageIndex = pageIndex, currentUrls[pageIndex] = options.url, !options.cancel && previousAnimatable && afterAnimate(allPages, pageIndex), view - }) + + if (options.cancel) { + return; } + + cancelActiveAnimations(); + + var selected = selectedPageIndex; + var previousAnimatable = selected === -1 ? null : allPages[selected]; + var pageIndex = selected + 1; + + if (pageIndex >= pageContainerCount) { + pageIndex = 0; + } + + var viewHtml = options.view; + + var properties = []; + if (options.fullscreen) { + properties.push('fullscreen'); + } + + var currentPage = allPages[pageIndex]; + + var view; + + if (currentPage) { + triggerDestroy(currentPage); + currentPage.insertAdjacentHTML('beforebegin', viewHtml); + view = findViewBefore(currentPage, 'view'); + + mainAnimatedPages.removeChild(currentPage); + + } else { + mainAnimatedPages.insertAdjacentHTML('beforeend', viewHtml); + + view = findLastView(mainAnimatedPages, 'view'); + } + + view.classList.add('mainAnimatedPage'); + + if (properties.length) { + view.setAttribute('data-properties', properties.join(',')); + } + + if (options.type) { + view.setAttribute('data-type', options.type); + } + + allPages[pageIndex] = view; + + if (onBeforeChange) { + onBeforeChange(view, false, options); + } + + beforeAnimate(allPages, pageIndex, selected); + + // animate here + return animate(view, previousAnimatable, options.transition, options.isBack).then(function () { + + selectedPageIndex = pageIndex; + currentUrls[pageIndex] = options.url; + if (!options.cancel && previousAnimatable) { + afterAnimate(allPages, pageIndex); + } + + return view; + }); } function beforeAnimate(allPages, newPageIndex, oldPageIndex) { - for (var i = 0, length = allPages.length; i < length; i++) newPageIndex === i || oldPageIndex === i || allPages[i].classList.add("hide") + for (var i = 0, length = allPages.length; i < length; i++) { + if (newPageIndex === i || oldPageIndex === i) { + //allPages[i].classList.remove('hide'); + } else { + allPages[i].classList.add('hide'); + } + } } function afterAnimate(allPages, newPageIndex) { - for (var i = 0, length = allPages.length; i < length; i++) newPageIndex === i || allPages[i].classList.add("hide") + for (var i = 0, length = allPages.length; i < length; i++) { + if (newPageIndex === i) { + //allPages[i].classList.remove('hide'); + } else { + allPages[i].classList.add('hide'); + } + } } function animate(newAnimatedPage, oldAnimatedPage, transition, isBack) { + if (enableAnimation() && oldAnimatedPage) { - if ("slide" === transition) return slide(newAnimatedPage, oldAnimatedPage, transition, isBack); - if ("fade" === transition) return fade(newAnimatedPage, oldAnimatedPage, transition, isBack); - clearAnimation(newAnimatedPage), oldAnimatedPage && clearAnimation(oldAnimatedPage) + if (transition === 'slide') { + return slide(newAnimatedPage, oldAnimatedPage, transition, isBack); + } else if (transition === 'fade') { + return fade(newAnimatedPage, oldAnimatedPage, transition, isBack); + } else { + clearAnimation(newAnimatedPage); + if (oldAnimatedPage) { + clearAnimation(oldAnimatedPage); + } + } } - return Promise.resolve() + + return Promise.resolve(); } function clearAnimation(elem) { - setAnimation(elem, "none") + setAnimation(elem, 'none'); } function slide(newAnimatedPage, oldAnimatedPage, transition, isBack) { - return new Promise(function(resolve, reject) { - var duration = layoutManager.tv ? 450 : 160, - animations = []; - oldAnimatedPage && (isBack ? setAnimation(oldAnimatedPage, "view-slideright-r " + duration + "ms ease-out normal both") : setAnimation(oldAnimatedPage, "view-slideleft-r " + duration + "ms ease-out normal both"), animations.push(oldAnimatedPage)), isBack ? setAnimation(newAnimatedPage, "view-slideright " + duration + "ms ease-out normal both") : setAnimation(newAnimatedPage, "view-slideleft " + duration + "ms ease-out normal both"), animations.push(newAnimatedPage), currentAnimations = animations; - var onAnimationComplete = function() { + + return new Promise(function (resolve, reject) { + + var duration = layoutManager.tv ? 450 : 160; + + var animations = []; + + if (oldAnimatedPage) { + if (isBack) { + setAnimation(oldAnimatedPage, 'view-slideright-r ' + duration + 'ms ease-out normal both'); + } else { + setAnimation(oldAnimatedPage, 'view-slideleft-r ' + duration + 'ms ease-out normal both'); + } + animations.push(oldAnimatedPage); + } + + if (isBack) { + setAnimation(newAnimatedPage, 'view-slideright ' + duration + 'ms ease-out normal both'); + } else { + setAnimation(newAnimatedPage, 'view-slideleft ' + duration + 'ms ease-out normal both'); + } + animations.push(newAnimatedPage); + + currentAnimations = animations; + + var onAnimationComplete = function () { dom.removeEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, { - once: !0 - }), resolve() + once: true + }); + resolve(); }; + dom.addEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, { - once: !0 - }) - }) + once: true + }); + }); } function fade(newAnimatedPage, oldAnimatedPage, transition, isBack) { - return new Promise(function(resolve, reject) { - var duration = layoutManager.tv ? 450 : 270, - animations = []; - newAnimatedPage.style.opacity = 0, setAnimation(newAnimatedPage, "view-fadein " + duration + "ms ease-in normal both"), animations.push(newAnimatedPage), oldAnimatedPage && (setAnimation(oldAnimatedPage, "view-fadeout " + duration + "ms ease-out normal both"), animations.push(oldAnimatedPage)), currentAnimations = animations; - var onAnimationComplete = function() { + + return new Promise(function (resolve, reject) { + + var duration = layoutManager.tv ? 450 : 270; + var animations = []; + + newAnimatedPage.style.opacity = 0; + setAnimation(newAnimatedPage, 'view-fadein ' + duration + 'ms ease-in normal both'); + animations.push(newAnimatedPage); + + if (oldAnimatedPage) { + setAnimation(oldAnimatedPage, 'view-fadeout ' + duration + 'ms ease-out normal both'); + animations.push(oldAnimatedPage); + } + + currentAnimations = animations; + + var onAnimationComplete = function () { dom.removeEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, { - once: !0 - }), resolve() + once: true + }); + resolve(); }; + dom.addEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, { - once: !0 - }) - }) + once: true + }); + }); } function setAnimation(elem, value) { - requestAnimationFrame(function() { - elem.style.animation = value - }) + + requestAnimationFrame(function () { + elem.style.animation = value; + }); } + var currentAnimations = []; function cancelActiveAnimations() { - for (var animations = currentAnimations, i = 0, length = animations.length; i < length; i++) animations[i].style.animation = "none" + + var animations = currentAnimations; + for (var i = 0, length = animations.length; i < length; i++) { + animations[i].style.animation = 'none'; + } } + var onBeforeChange; function setOnBeforeChange(fn) { - onBeforeChange = fn + onBeforeChange = fn; } function tryRestoreView(options) { - var url = options.url, - index = currentUrls.indexOf(url); - if (-1 !== index) { - var animatable = allPages[index], - view = animatable; + + var url = options.url; + var index = currentUrls.indexOf(url); + + if (index !== -1) { + + var animatable = allPages[index]; + var view = animatable; + if (view) { - if (options.cancel) return; + + if (options.cancel) { + return; + } + cancelActiveAnimations(); - var selected = selectedPageIndex, - previousAnimatable = -1 === selected ? null : allPages[selected]; - return onBeforeChange && onBeforeChange(view, !0, options), beforeAnimate(allPages, index, selected), animatable.classList.remove("hide"), animate(animatable, previousAnimatable, options.transition, options.isBack).then(function() { - return selectedPageIndex = index, !options.cancel && previousAnimatable && afterAnimate(allPages, index), view - }) + + var selected = selectedPageIndex; + var previousAnimatable = selected === -1 ? null : allPages[selected]; + + if (onBeforeChange) { + onBeforeChange(view, true, options); + } + + beforeAnimate(allPages, index, selected); + + animatable.classList.remove('hide'); + + return animate(animatable, previousAnimatable, options.transition, options.isBack).then(function () { + + selectedPageIndex = index; + if (!options.cancel && previousAnimatable) { + afterAnimate(allPages, index); + } + return view; + }); } } - return Promise.reject() + + return Promise.reject(); } function triggerDestroy(view) { - view.dispatchEvent(new CustomEvent("viewdestroy", { - cancelable: !1 - })) + + view.dispatchEvent(new CustomEvent('viewdestroy', { + cancelable: false + })); } function reset() { - allPages = [], currentUrls = [], mainAnimatedPages.innerHTML = "", selectedPageIndex = -1 + + allPages = []; + currentUrls = []; + mainAnimatedPages.innerHTML = ''; + selectedPageIndex = -1; } - var onBeforeChange, mainAnimatedPages = document.querySelector(".mainAnimatedPages"), - allPages = [], - currentUrls = [], - pageContainerCount = 3, - selectedPageIndex = -1, - currentAnimations = []; + return { loadView: loadView, tryRestoreView: tryRestoreView, reset: reset, setOnBeforeChange: setOnBeforeChange - } + }; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/viewmanager/viewmanager.js b/src/bower_components/emby-webcomponents/viewmanager/viewmanager.js index 3ab5afa710..606c7e98c1 100644 --- a/src/bower_components/emby-webcomponents/viewmanager/viewmanager.js +++ b/src/bower_components/emby-webcomponents/viewmanager/viewmanager.js @@ -1,82 +1,183 @@ -define(["viewcontainer", "focusManager", "queryString", "layoutManager"], function(viewcontainer, focusManager, queryString, layoutManager) { - "use strict"; +define(['viewcontainer', 'focusManager', 'queryString', 'layoutManager'], function (viewcontainer, focusManager, queryString, layoutManager) { + 'use strict'; + + var currentView; + var dispatchPageEvents; + + viewcontainer.setOnBeforeChange(function (newView, isRestored, options) { + + var lastView = currentView; + if (lastView) { + + var beforeHideResult = dispatchViewEvent(lastView, null, 'viewbeforehide', true); + + if (!beforeHideResult) { + // todo: cancel + } + } + + var eventDetail = getViewEventDetail(newView, options, isRestored); + + if (!newView.initComplete) { + newView.initComplete = true; + + if (options.controllerFactory) { + + // Use controller method + var controller = new options.controllerFactory(newView, eventDetail.detail.params); + } + + if (!options.controllerFactory || dispatchPageEvents) { + dispatchViewEvent(newView, eventDetail, 'viewinit'); + } + } + + dispatchViewEvent(newView, eventDetail, 'viewbeforeshow'); + }); function onViewChange(view, options, isRestore) { + var lastView = currentView; - lastView && dispatchViewEvent(lastView, null, "viewhide"), currentView = view; + if (lastView) { + dispatchViewEvent(lastView, null, 'viewhide'); + } + + currentView = view; + var eventDetail = getViewEventDetail(view, options, isRestore); - isRestore ? layoutManager.mobile || (view.activeElement && document.body.contains(view.activeElement) && focusManager.isCurrentlyFocusable(view.activeElement) ? focusManager.focus(view.activeElement) : focusManager.autoFocus(view)) : !1 !== options.autoFocus && focusManager.autoFocus(view), view.dispatchEvent(new CustomEvent("viewshow", eventDetail)), dispatchPageEvents && view.dispatchEvent(new CustomEvent("pageshow", eventDetail)) + + if (!isRestore) { + if (options.autoFocus !== false) { + focusManager.autoFocus(view); + } + } + else if (!layoutManager.mobile) { + if (view.activeElement && document.body.contains(view.activeElement) && focusManager.isCurrentlyFocusable(view.activeElement)) { + focusManager.focus(view.activeElement); + } else { + focusManager.autoFocus(view); + } + } + + view.dispatchEvent(new CustomEvent('viewshow', eventDetail)); + + if (dispatchPageEvents) { + view.dispatchEvent(new CustomEvent('pageshow', eventDetail)); + } } function getProperties(view) { - var props = view.getAttribute("data-properties"); - return props ? props.split(",") : [] + var props = view.getAttribute('data-properties'); + + if (props) { + return props.split(','); + } + + return []; } function dispatchViewEvent(view, eventInfo, eventName, isCancellable) { - eventInfo || (eventInfo = { - detail: { - type: view.getAttribute("data-type"), - properties: getProperties(view) - }, - bubbles: !0, - cancelable: isCancellable - }), eventInfo.cancelable = isCancellable || !1; + + if (!eventInfo) { + eventInfo = { + detail: { + type: view.getAttribute('data-type'), + properties: getProperties(view) + }, + bubbles: true, + cancelable: isCancellable + }; + } + + eventInfo.cancelable = isCancellable || false; + var eventResult = view.dispatchEvent(new CustomEvent(eventName, eventInfo)); - return dispatchPageEvents && (eventInfo.cancelable = !1, view.dispatchEvent(new CustomEvent(eventName.replace("view", "page"), eventInfo))), eventResult + + if (dispatchPageEvents) { + eventInfo.cancelable = false; + view.dispatchEvent(new CustomEvent(eventName.replace('view', 'page'), eventInfo)); + } + + return eventResult; } function getViewEventDetail(view, options, isRestore) { - var url = options.url, - index = url.indexOf("?"), - params = -1 === index ? {} : queryString.parse(url.substring(index + 1)); + + var url = options.url; + var index = url.indexOf('?'); + var params = index === -1 ? {} : queryString.parse(url.substring(index + 1)); + return { detail: { - type: view.getAttribute("data-type"), + type: view.getAttribute('data-type'), properties: getProperties(view), params: params, isRestored: isRestore, state: options.state, + + // The route options options: options.options || {} }, - bubbles: !0, - cancelable: !1 - } + bubbles: true, + cancelable: false + }; } function resetCachedViews() { - viewcontainer.reset() + // Reset all cached views whenever the skin changes + viewcontainer.reset(); } - function ViewManager() {} - var currentView, dispatchPageEvents; - return viewcontainer.setOnBeforeChange(function(newView, isRestored, options) { + document.addEventListener('skinunload', resetCachedViews); + + function ViewManager() { + } + + ViewManager.prototype.loadView = function (options) { + var lastView = currentView; + + // Record the element that has focus if (lastView) { - dispatchViewEvent(lastView, null, "viewbeforehide", !0) + lastView.activeElement = document.activeElement; } - var eventDetail = getViewEventDetail(newView, options, isRestored); - if (!newView.initComplete) { - if (newView.initComplete = !0, options.controllerFactory) { - new options.controllerFactory(newView, eventDetail.detail.params) - } - options.controllerFactory && !dispatchPageEvents || dispatchViewEvent(newView, eventDetail, "viewinit") + + if (options.cancel) { + return; } - dispatchViewEvent(newView, eventDetail, "viewbeforeshow") - }), document.addEventListener("skinunload", resetCachedViews), ViewManager.prototype.loadView = function(options) { - var lastView = currentView; - lastView && (lastView.activeElement = document.activeElement), options.cancel || viewcontainer.loadView(options).then(function(view) { - onViewChange(view, options) - }) - }, ViewManager.prototype.tryRestoreView = function(options, onViewChanging) { - return options.cancel ? Promise.reject({ - cancelled: !0 - }) : (currentView && (currentView.activeElement = document.activeElement), viewcontainer.tryRestoreView(options).then(function(view) { - onViewChanging(), onViewChange(view, options, !0) - })) - }, ViewManager.prototype.currentView = function() { - return currentView - }, ViewManager.prototype.dispatchPageEvents = function(value) { - dispatchPageEvents = value - }, new ViewManager -}); \ No newline at end of file + + viewcontainer.loadView(options).then(function (view) { + + onViewChange(view, options); + }); + }; + + ViewManager.prototype.tryRestoreView = function (options, onViewChanging) { + + if (options.cancel) { + return Promise.reject({ cancelled: true }); + } + + // Record the element that has focus + if (currentView) { + currentView.activeElement = document.activeElement; + } + + return viewcontainer.tryRestoreView(options).then(function (view) { + + onViewChanging(); + onViewChange(view, options, true); + + }); + }; + + ViewManager.prototype.currentView = function () { + return currentView; + }; + + ViewManager.prototype.dispatchPageEvents = function (value) { + dispatchPageEvents = value; + }; + + return new ViewManager(); +}); diff --git a/src/bower_components/emby-webcomponents/viewsettings/viewsettings.js b/src/bower_components/emby-webcomponents/viewsettings/viewsettings.js index 9fd54e6db5..7600932036 100644 --- a/src/bower_components/emby-webcomponents/viewsettings/viewsettings.js +++ b/src/bower_components/emby-webcomponents/viewsettings/viewsettings.js @@ -1,60 +1,146 @@ -define(["require", "dialogHelper", "loading", "apphost", "layoutManager", "connectionManager", "appRouter", "globalize", "userSettings", "emby-checkbox", "emby-input", "paper-icon-button-light", "emby-select", "material-icons", "css!./../formdialog", "emby-button", "emby-linkbutton", "flexStyles"], function(require, dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize, userSettings) { - "use strict"; +define(['require', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (require, dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize, userSettings) { + 'use strict'; function onSubmit(e) { - return e.preventDefault(), !1 + + e.preventDefault(); + return false; } function initEditor(context, settings) { - context.querySelector("form").addEventListener("submit", onSubmit); - for (var elems = context.querySelectorAll(".viewSetting-checkboxContainer"), i = 0, length = elems.length; i < length; i++) elems[i].querySelector("input").checked = settings[elems[i].getAttribute("data-settingname")] || !1; - context.querySelector(".selectImageType").value = settings.imageType || "primary" + + context.querySelector('form').addEventListener('submit', onSubmit); + + var elems = context.querySelectorAll('.viewSetting-checkboxContainer'); + + for (var i = 0, length = elems.length; i < length; i++) { + + elems[i].querySelector('input').checked = settings[elems[i].getAttribute('data-settingname')] || false; + } + + context.querySelector('.selectImageType').value = settings.imageType || 'primary'; } function saveValues(context, settings, settingsKey) { - for (var elems = context.querySelectorAll(".viewSetting-checkboxContainer"), i = 0, length = elems.length; i < length; i++) userSettings.set(settingsKey + "-" + elems[i].getAttribute("data-settingname"), elems[i].querySelector("input").checked); - userSettings.set(settingsKey + "-imageType", context.querySelector(".selectImageType").value) - } + + var elems = context.querySelectorAll('.viewSetting-checkboxContainer'); + for (var i = 0, length = elems.length; i < length; i++) { + userSettings.set(settingsKey + '-' + elems[i].getAttribute('data-settingname'), elems[i].querySelector('input').checked); + } + + userSettings.set(settingsKey + '-imageType', context.querySelector('.selectImageType').value); + } function centerFocus(elem, horiz, on) { - require(["scrollHelper"], function(scrollHelper) { - var fn = on ? "on" : "off"; - scrollHelper.centerFocus[fn](elem, horiz) - }) + require(['scrollHelper'], function (scrollHelper) { + var fn = on ? 'on' : 'off'; + scrollHelper.centerFocus[fn](elem, horiz); + }); } function showIfAllowed(context, selector, visible) { + var elem = context.querySelector(selector); - visible && !elem.classList.contains("hiddenFromViewSettings") ? elem.classList.remove("hide") : elem.classList.add("hide") + + if (visible && !elem.classList.contains('hiddenFromViewSettings')) { + elem.classList.remove('hide'); + } else { + elem.classList.add('hide'); + } } - function ViewSettings() {} - return ViewSettings.prototype.show = function(options) { - return new Promise(function(resolve, reject) { - require(["text!./viewsettings.template.html"], function(template) { + function ViewSettings() { + + } + + ViewSettings.prototype.show = function (options) { + + return new Promise(function (resolve, reject) { + + require(['text!./viewsettings.template.html'], function (template) { + var dialogOptions = { - removeOnClose: !0, - scrollY: !1 + removeOnClose: true, + scrollY: false }; - layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small"; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; + } else { + dialogOptions.size = 'small'; + } + var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - var html = ""; - html += '
    ', html += '', html += '

    ${Settings}

    ', html += "
    ", html += template, dlg.innerHTML = globalize.translateDocument(html, "sharedcomponents"); - for (var settingElements = dlg.querySelectorAll(".viewSetting"), i = 0, length = settingElements.length; i < length; i++) - 1 === options.visibleSettings.indexOf(settingElements[i].getAttribute("data-settingname")) ? (settingElements[i].classList.add("hide"), settingElements[i].classList.add("hiddenFromViewSettings")) : (settingElements[i].classList.remove("hide"), settingElements[i].classList.remove("hiddenFromViewSettings")); - initEditor(dlg, options.settings), dlg.querySelector(".selectImageType").addEventListener("change", function() { - showIfAllowed(dlg, ".chkTitleContainer", "list" !== this.value), showIfAllowed(dlg, ".chkYearContainer", "list" !== this.value) - }), dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) - }), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0); + + dlg.classList.add('formDialog'); + + var html = ''; + + html += '
    '; + html += ''; + html += '

    ${Settings}

    '; + + html += '
    '; + + html += template; + + dlg.innerHTML = globalize.translateDocument(html, 'sharedcomponents'); + + var settingElements = dlg.querySelectorAll('.viewSetting'); + for (var i = 0, length = settingElements.length; i < length; i++) { + if (options.visibleSettings.indexOf(settingElements[i].getAttribute('data-settingname')) === -1) { + settingElements[i].classList.add('hide'); + settingElements[i].classList.add('hiddenFromViewSettings'); + } else { + settingElements[i].classList.remove('hide'); + settingElements[i].classList.remove('hiddenFromViewSettings'); + } + } + + initEditor(dlg, options.settings); + + dlg.querySelector('.selectImageType').addEventListener('change', function () { + + showIfAllowed(dlg, '.chkTitleContainer', this.value !== 'list'); + showIfAllowed(dlg, '.chkYearContainer', this.value !== 'list'); + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + + dialogHelper.close(dlg); + }); + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, true); + } + var submitted; - dlg.querySelector(".selectImageType").dispatchEvent(new CustomEvent("change", {})), dlg.querySelector("form").addEventListener("change", function() { - submitted = !0 - }, !0), dialogHelper.open(dlg).then(function() { - if (layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), submitted) return saveValues(dlg, options.settings, options.settingsKey), void resolve(); - reject() - }) - }) - }) - }, ViewSettings + + dlg.querySelector('.selectImageType').dispatchEvent(new CustomEvent('change', {})); + + dlg.querySelector('form').addEventListener('change', function () { + + submitted = true; + + }, true); + + dialogHelper.open(dlg).then(function () { + + if (layoutManager.tv) { + centerFocus(dlg.querySelector('.formDialogContent'), false, false); + } + + if (submitted) { + saveValues(dlg, options.settings, options.settingsKey); + resolve(); + return; + } + + reject(); + }); + }); + }); + }; + + return ViewSettings; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/visibleinviewport.js b/src/bower_components/emby-webcomponents/visibleinviewport.js index 60f5fd9dee..5f6064ff96 100644 --- a/src/bower_components/emby-webcomponents/visibleinviewport.js +++ b/src/bower_components/emby-webcomponents/visibleinviewport.js @@ -1,19 +1,41 @@ -define(["dom"], function(dom) { - "use strict"; +define(['dom'], function (dom) { + 'use strict'; + /** + * Copyright 2012, Digital Fusion + * Licensed under the MIT license. + * http://teamdf.com/jquery-plugins/license/ + * + * @author Sam Sehnert + * @desc A small plugin that checks whether elements are within + * the user visible viewport of a web browser. + * only accounts for vertical position, not horizontal. + */ function visibleInViewport(elem, partial, thresholdX, thresholdY) { - if (thresholdX = thresholdX || 0, thresholdY = thresholdY || 0, !elem.getBoundingClientRect) return !0; - var windowSize = dom.getWindowSize(), - vpWidth = windowSize.innerWidth, - vpHeight = windowSize.innerHeight, - rec = elem.getBoundingClientRect(), + + thresholdX = thresholdX || 0; + thresholdY = thresholdY || 0; + + if (!elem.getBoundingClientRect) { + return true; + } + + var windowSize = dom.getWindowSize(); + + var vpWidth = windowSize.innerWidth, + vpHeight = windowSize.innerHeight; + + // Use this native browser method, if available. + var rec = elem.getBoundingClientRect(), tViz = rec.top >= 0 && rec.top < vpHeight + thresholdY, bViz = rec.bottom > 0 && rec.bottom <= vpHeight + thresholdY, lViz = rec.left >= 0 && rec.left < vpWidth + thresholdX, rViz = rec.right > 0 && rec.right <= vpWidth + thresholdX, vVisible = partial ? tViz || bViz : tViz && bViz, hVisible = partial ? lViz || rViz : lViz && rViz; - return vVisible && hVisible + + return vVisible && hVisible; } - return visibleInViewport + + return visibleInViewport; }); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/youtubeplayer/plugin.js b/src/bower_components/emby-webcomponents/youtubeplayer/plugin.js index 243050eccb..1ed95e2110 100644 --- a/src/bower_components/emby-webcomponents/youtubeplayer/plugin.js +++ b/src/bower_components/emby-webcomponents/youtubeplayer/plugin.js @@ -1,181 +1,409 @@ -define(["require", "events", "browser", "appRouter", "loading"], function(require, events, browser, appRouter, loading) { +define(['require', 'events', 'browser', 'appRouter', 'loading'], function (require, events, browser, appRouter, loading) { "use strict"; function zoomIn(elem, iterations) { - var keyframes = [{ - transform: "scale3d(.2, .2, .2) ", - opacity: ".6", - offset: 0 - }, { - transform: "none", - opacity: "1", - offset: 1 - }], - timing = { - duration: 240, - iterations: iterations - }; - return elem.animate(keyframes, timing) + var keyframes = [ + { transform: 'scale3d(.2, .2, .2) ', opacity: '.6', offset: 0 }, + { transform: 'none', opacity: '1', offset: 1 } + ]; + + var timing = { duration: 240, iterations: iterations }; + return elem.animate(keyframes, timing); } function createMediaElement(instance, options) { - return new Promise(function(resolve, reject) { - var dlg = document.querySelector(".youtubePlayerContainer"); - dlg ? resolve(dlg.querySelector("#player")) : require(["css!./style"], function() { - loading.show(); - var dlg = document.createElement("div"); - dlg.classList.add("youtubePlayerContainer"), options.fullscreen && dlg.classList.add("onTop"), dlg.innerHTML = '
    '; - var videoElement = dlg.querySelector("#player"); - document.body.insertBefore(dlg, document.body.firstChild), instance.videoDialog = dlg, options.fullscreen && dlg.animate && !browser.slow ? zoomIn(dlg, 1).onfinish = function() { - resolve(videoElement) - } : resolve(videoElement) - }) - }) + + return new Promise(function (resolve, reject) { + + var dlg = document.querySelector('.youtubePlayerContainer'); + + if (!dlg) { + + require(['css!./style'], function () { + + loading.show(); + + var dlg = document.createElement('div'); + + dlg.classList.add('youtubePlayerContainer'); + + if (options.fullscreen) { + dlg.classList.add('onTop'); + } + + dlg.innerHTML = '
    '; + var videoElement = dlg.querySelector('#player'); + + document.body.insertBefore(dlg, document.body.firstChild); + instance.videoDialog = dlg; + + if (options.fullscreen && dlg.animate && !browser.slow) { + zoomIn(dlg, 1).onfinish = function () { + resolve(videoElement); + }; + } else { + resolve(videoElement); + } + + }); + + } else { + resolve(dlg.querySelector('#player')); + } + }); } function onVideoResize() { - var instance = this, - player = instance.currentYoutubePlayer, - dlg = instance.videoDialog; - player && dlg && player.setSize(dlg.offsetWidth, dlg.offsetHeight) + var instance = this; + var player = instance.currentYoutubePlayer; + var dlg = instance.videoDialog; + if (player && dlg) { + player.setSize(dlg.offsetWidth, dlg.offsetHeight); + } } function clearTimeUpdateInterval(instance) { - instance.timeUpdateInterval && clearInterval(instance.timeUpdateInterval), instance.timeUpdateInterval = null + if (instance.timeUpdateInterval) { + clearInterval(instance.timeUpdateInterval); + } + instance.timeUpdateInterval = null; } function onEndedInternal(instance) { + clearTimeUpdateInterval(instance); var resizeListener = instance.resizeListener; - resizeListener && (window.removeEventListener("resize", resizeListener), window.removeEventListener("orientationChange", resizeListener), instance.resizeListener = null); + if (resizeListener) { + window.removeEventListener('resize', resizeListener); + window.removeEventListener('orientationChange', resizeListener); + instance.resizeListener = null; + } + var stopInfo = { src: instance._currentSrc }; - events.trigger(instance, "stopped", [stopInfo]), instance._currentSrc = null, instance.currentYoutubePlayer && instance.currentYoutubePlayer.destroy(), instance.currentYoutubePlayer = null + + events.trigger(instance, 'stopped', [stopInfo]); + + instance._currentSrc = null; + if (instance.currentYoutubePlayer) { + instance.currentYoutubePlayer.destroy(); + } + instance.currentYoutubePlayer = null; } + // 4. The API will call this function when the video player is ready. function onPlayerReady(event) { - event.target.playVideo() + event.target.playVideo(); } function onTimeUpdate(e) { - events.trigger(this, "timeupdate") + + events.trigger(this, 'timeupdate'); } function onPlaying(instance, playOptions, resolve) { - instance.started || (instance.started = !0, resolve(), clearTimeUpdateInterval(instance), instance.timeUpdateInterval = setInterval(onTimeUpdate.bind(instance), 500), playOptions.fullscreen ? appRouter.showVideoOsd().then(function() { - instance.videoDialog.classList.remove("onTop") - }) : (appRouter.setTransparency("backdrop"), instance.videoDialog.classList.remove("onTop")), require(["loading"], function(loading) { - loading.hide() - })) + + if (!instance.started) { + + instance.started = true; + resolve(); + clearTimeUpdateInterval(instance); + instance.timeUpdateInterval = setInterval(onTimeUpdate.bind(instance), 500); + + if (playOptions.fullscreen) { + + appRouter.showVideoOsd().then(function () { + instance.videoDialog.classList.remove('onTop'); + }); + + } else { + appRouter.setTransparency('backdrop'); + instance.videoDialog.classList.remove('onTop'); + } + + require(['loading'], function (loading) { + + loading.hide(); + }); + } } function setCurrentSrc(instance, elem, options) { - return new Promise(function(resolve, reject) { - require(["queryString"], function(queryString) { + + return new Promise(function (resolve, reject) { + + require(['queryString'], function (queryString) { + + instance._currentSrc = options.url; - var params = queryString.parse(options.url.split("?")[1]); - if (window.onYouTubeIframeAPIReady = function() { - instance.currentYoutubePlayer = new YT.Player("player", { - height: instance.videoDialog.offsetHeight, - width: instance.videoDialog.offsetWidth, - videoId: params.v, - events: { - onReady: onPlayerReady, - onStateChange: function(event) { - event.data === YT.PlayerState.PLAYING ? onPlaying(instance, options, resolve) : event.data === YT.PlayerState.ENDED ? onEndedInternal(instance) : event.data === YT.PlayerState.PAUSED && events.trigger(instance, "pause") + var params = queryString.parse(options.url.split('?')[1]); + // 3. This function creates an